sw/inc/ndtxt.hxx | 12 +++++ sw/source/core/doc/doc.cxx | 19 ++++---- sw/source/core/doc/docedt.cxx | 19 +++++++- sw/source/core/doc/doclay.cxx | 17 ++++++- sw/source/core/docnode/node.cxx | 36 ++++++++++------ sw/source/core/txtnode/ndtxt.cxx | 63 ++++++++++++++++++++-------- sw/source/core/txtnode/thints.cxx | 25 ++++++++++- sw/source/core/txtnode/txtedt.cxx | 17 ++++++- sw/source/core/undo/undel.cxx | 10 ++-- sw/source/core/undo/unins.cxx | 25 ++++------- sw/source/core/undo/unovwr.cxx | 14 ++++-- sw/source/filter/xml/xmltbli.cxx | 83 ++++++++++++++++++++++++++++---------- sw/source/filter/xml/xmltbli.hxx | 2 13 files changed, 245 insertions(+), 97 deletions(-)
New commits: commit 1b5839f49c07beb6fbde6c7370a5636d22f9ab77 Author: Michael Stahl <[email protected]> Date: Fri Feb 15 22:36:55 2013 +0100 fdo#60842: sw ODF import: support value-type="string" on cells: According to ODF 1.2 part 1 19.385 office:value-type, the attributes of table:table-cell, namely office:value-type="string" and office:string-value="foo", should override the element content of the cell. Change-Id: Ic580307effb046d127c4d64a4f963f0e91b3a2d1 diff --git a/sw/source/filter/xml/xmltbli.cxx b/sw/source/filter/xml/xmltbli.cxx index 378a307..d35254d 100644 --- a/sw/source/filter/xml/xmltbli.cxx +++ b/sw/source/filter/xml/xmltbli.cxx @@ -95,6 +95,7 @@ enum SwXMLTableCellAttrTokens XML_TOK_TABLE_BOOLEAN_VALUE, XML_TOK_TABLE_PROTECTED, XML_TOK_TABLE_STRING_VALUE, + XML_TOK_TABLE_VALUE_TYPE, XML_TOK_TABLE_CELL_ATTR_END=XML_TOK_UNKNOWN }; @@ -136,6 +137,7 @@ static SvXMLTokenMapEntry aTableCellAttrTokenMap[] = { XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TOK_TABLE_PROTECTED }, { XML_NAMESPACE_TABLE, XML_PROTECT, XML_TOK_TABLE_PROTECTED }, // for backwards compatibility with SRC629 (and before) { XML_NAMESPACE_OFFICE, XML_STRING_VALUE, XML_TOK_TABLE_STRING_VALUE }, + { XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_TOK_TABLE_VALUE_TYPE }, XML_TOKEN_MAP_END }; @@ -162,6 +164,7 @@ class SwXMLTableCell_Impl OUString aStyleName; OUString mXmlId; + OUString m_StringValue; OUString sFormula; // cell formula; valid if length > 0 double dValue; // formula value @@ -175,7 +178,7 @@ class SwXMLTableCell_Impl sal_Bool bProtected : 1; sal_Bool bHasValue; // determines whether dValue attribute is valid sal_Bool mbCovered; - sal_Bool mbTextValue; + bool m_bHasStringValue; public: @@ -185,18 +188,19 @@ public: nColSpan( nCSpan ), bProtected( sal_False ), mbCovered( sal_False ) + , m_bHasStringValue(false) {} inline void Set( const OUString& rStyleName, sal_uInt32 nRSpan, sal_uInt32 nCSpan, const SwStartNode *pStNd, SwXMLTableContext *pTable, - sal_Bool bProtect = sal_False, - const OUString* pFormula = NULL, - sal_Bool bHasValue = sal_False, - sal_Bool mbCovered = sal_False, - double dVal = 0.0, - sal_Bool mbTextValue = sal_False, - OUString const& i_rXmlId = OUString()); + sal_Bool bProtect, + const OUString* pFormula, + sal_Bool bHasValue, + sal_Bool bCovered, + double dVal, + OUString const*const pStringValue, + OUString const& i_rXmlId); bool IsUsed() const { return pStartNode!=0 || xSubTable.Is() || bProtected;} @@ -210,7 +214,10 @@ public: sal_Bool HasValue() const { return bHasValue; } sal_Bool IsProtected() const { return bProtected; } sal_Bool IsCovered() const { return mbCovered; } - sal_Bool HasTextValue() const { return mbTextValue; } + bool HasStringValue() const { return m_bHasStringValue; } + OUString const* GetStringValue() const { + return (m_bHasStringValue) ? &m_StringValue : 0; + } const OUString& GetXmlId() const { return mXmlId; } const SwStartNode *GetStartNode() const { return pStartNode; } @@ -230,7 +237,7 @@ inline void SwXMLTableCell_Impl::Set( const OUString& rStyleName, sal_Bool bHasVal, sal_Bool bCov, double dVal, - sal_Bool bTextVal, + OUString const*const pStringValue, OUString const& i_rXmlId ) { aStyleName = rStyleName; @@ -241,7 +248,11 @@ inline void SwXMLTableCell_Impl::Set( const OUString& rStyleName, dValue = dVal; bHasValue = bHasVal; mbCovered = bCov; - mbTextValue = bTextVal; + if (pStringValue) + { + m_StringValue = *pStringValue; + } + m_bHasStringValue = (pStringValue != 0); bProtected = bProtect; if (!mbCovered) // ensure uniqueness @@ -396,12 +407,14 @@ class SwXMLTableCellContext_Impl : public SvXMLImportContext OUString sFormula; OUString sSaveParaDefault; OUString mXmlId; + OUString m_StringValue; SvXMLImportContextRef xMyTable; double fValue; sal_Bool bHasValue; - sal_Bool bHasTextValue; + bool m_bHasStringValue; + bool m_bValueTypeIsString; sal_Bool bProtect; sal_uInt32 nRowSpan; @@ -445,7 +458,8 @@ SwXMLTableCellContext_Impl::SwXMLTableCellContext_Impl( xMyTable( pTable ), fValue( 0.0 ), bHasValue( sal_False ), - bHasTextValue( sal_False ), + m_bHasStringValue(false), + m_bValueTypeIsString(false), bProtect( sal_False ), nRowSpan( 1UL ), nColSpan( 1UL ), @@ -550,7 +564,19 @@ SwXMLTableCellContext_Impl::SwXMLTableCellContext_Impl( break; case XML_TOK_TABLE_STRING_VALUE: { - bHasTextValue = sal_True; + m_StringValue = rValue; + m_bHasStringValue = true; + } + break; + case XML_TOK_TABLE_VALUE_TYPE: + { + if ("string" == rValue) + { + m_bValueTypeIsString = true; + } + // ignore other types - it would be correct to require + // matching value-type and $type-value attributes, + // but we've been reading those without checking forever. } break; } @@ -566,7 +592,8 @@ inline void SwXMLTableCellContext_Impl::_InsertContent() GetTable()->InsertCell( aStyleName, nRowSpan, nColSpan, GetTable()->InsertTableSection(), mXmlId, - NULL, bProtect, &sFormula, bHasValue, fValue, bHasTextValue ); + NULL, bProtect, &sFormula, bHasValue, fValue, + (m_bHasStringValue && m_bValueTypeIsString) ? &m_StringValue : 0); } inline void SwXMLTableCellContext_Impl::InsertContent() @@ -643,9 +670,13 @@ SvXMLImportContext *SwXMLTableCellContext_Impl::CreateChildContext( { if( GetTable()->IsValid() ) InsertContentIfNotThere(); - pContext = GetImport().GetTextImport()->CreateTextChildContext( + // fdo#60842: "office:string-value" overrides text content -> no import + if (!(m_bValueTypeIsString && m_bHasStringValue)) + { + pContext = GetImport().GetTextImport()->CreateTextChildContext( GetImport(), nPrefix, rLocalName, xAttrList, XML_TEXT_TYPE_CELL ); + } } if( !pContext ) @@ -1579,7 +1610,7 @@ void SwXMLTableContext::InsertCell( const OUString& rStyleName, const OUString* pFormula, sal_Bool bHasValue, double fValue, - sal_Bool bTextValue ) + OUString const*const pStringValue ) { OSL_ENSURE( nCurCol < GetColumnCount(), "SwXMLTableContext::InsertCell: row is full" ); @@ -1673,7 +1704,7 @@ void SwXMLTableContext::InsertCell( const OUString& rStyleName, GetCell( nRowsReq-j, nColsReq-i ) ->Set( sStyleName, j, i, pStartNode, pTable, bProtect, pFormula, bHasValue, bCovered, fValue, - bTextValue, i_rXmlId ); + pStringValue, i_rXmlId ); } } @@ -1742,7 +1773,7 @@ void SwXMLTableContext::InsertRepRows( sal_uInt32 nCount ) 0, pSrcCell->IsProtected(), &pSrcCell->GetFormula(), pSrcCell->HasValue(), pSrcCell->GetValue(), - pSrcCell->HasTextValue() ); + pSrcCell->GetStringValue() ); } } FinishRow(); @@ -2076,6 +2107,18 @@ SwTableBox *SwXMLTableContext::MakeTableBox( if( pCell->GetStartNode() ) { + if (pCell->HasStringValue()) + { + SwNodeIndex const aNodeIndex(*(pCell->GetStartNode()), 1); + SwTxtNode *const pTxtNode(aNodeIndex.GetNode().GetTxtNode()); + SAL_WARN_IF(!pTxtNode, "sw", "Should have a text node in cell?"); + if (pTxtNode) + { + SAL_WARN_IF(pTxtNode->GetTxt().Len(), "sw", "why text here?"); + pTxtNode->InsertText(*pCell->GetStringValue(), + SwIndex(pTxtNode, 0)); + } + } // try to rescue broken documents with a certain pattern // if: 1) the cell has a default number format (number 0) @@ -2139,7 +2182,7 @@ SwTableBox *SwXMLTableContext::MakeTableBox( SwTblBoxFormula aFormulaItem( rFormula ); pBoxFmt2->SetFmtAttr( aFormulaItem ); } - else if( !pCell->HasValue() && pCell->HasTextValue() ) + else if (!pCell->HasValue() && pCell->HasStringValue()) { // Check for another inconsistency: // No value but a non-textual format, i.e. a number format diff --git a/sw/source/filter/xml/xmltbli.hxx b/sw/source/filter/xml/xmltbli.hxx index 06329c5..f6d9da9 100644 --- a/sw/source/filter/xml/xmltbli.hxx +++ b/sw/source/filter/xml/xmltbli.hxx @@ -177,7 +177,7 @@ public: const ::rtl::OUString *pFormula=0, sal_Bool bHasValue = sal_False, double fValue = 0.0, - sal_Bool bTextValue = sal_False ); + ::rtl::OUString const*const pStringValue = 0); void InsertRow( const ::rtl::OUString& rStyleName, const ::rtl::OUString& rDfltCellStyleName, bool bInHead, commit 0e49d87d92a3f1aeeeda547f1a7e710dcd4fee95 Author: Michael Stahl <[email protected]> Date: Fri Feb 15 16:27:34 2013 +0100 fdo#60732: check max size in SwTxtNode::ReplaceTextOnly Change-Id: I1ca2075ab99fe1b09df700f55645b44f38cf5bcc diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx index 3c8503b..40327cb 100644 --- a/sw/source/core/txtnode/txtedt.cxx +++ b/sw/source/core/txtnode/txtedt.cxx @@ -1799,9 +1799,19 @@ void SwTxtNode::TransliterateText( { // now apply the changes from end to start to leave the offsets of the // yet unchanged text parts remain the same. + size_t nSum(m_Text.Len()); for (size_t i = 0; i < aChanges.size(); ++i) - { - swTransliterationChgData &rData = aChanges[ aChanges.size() - 1 - i ]; + { // check this here since AddChanges cannot be moved below + // call to ReplaceTextOnly + swTransliterationChgData & rData = + aChanges[ aChanges.size() - 1 - i ]; + nSum = nSum + rData.sChanged.Len() - rData.nLen; + if (nSum > TXTNODE_MAX) + { + SAL_WARN("sw.core", "SwTxtNode::ReplaceTextOnly: " + "node text with insertion > TXTNODE_MAX."); + return; + } if (pUndo) pUndo->AddChanges( *this, rData.nStart, rData.nLen, rData.aOffsets ); ReplaceTextOnly( rData.nStart, rData.nLen, rData.sChanged, rData.aOffsets ); @@ -1814,6 +1824,9 @@ void SwTxtNode::ReplaceTextOnly( xub_StrLen nPos, xub_StrLen nLen, const XubString& rText, const Sequence<sal_Int32>& rOffsets ) { + assert(static_cast<size_t>(m_Text.Len()) + + static_cast<size_t>(rText.Len()) - nLen <= TXTNODE_MAX); + m_Text.Replace( nPos, nLen, rText ); xub_StrLen nTLen = rText.Len(); commit b6d45f26ea5bcc848737921b59a16253eb1d8587 Author: Michael Stahl <[email protected]> Date: Fri Feb 15 15:28:24 2013 +0100 fdo#60732: check max size in SwTxtNode::ReplaceText Also adjust SwUndoReplace to not assume that everything was inserted and use the stored indexes instead in Undo. Change-Id: I52f3aaf063c2b1bd52381bdc19e29a41a12c3847 diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index 0c48f64..fb46717 100644 --- a/sw/inc/ndtxt.hxx +++ b/sw/inc/ndtxt.hxx @@ -333,6 +333,8 @@ public: const SwIndex & rStart, const xub_StrLen nLen); /// replace nDelLen characters at rStart with rText + /// in case the replacement does not fit, it is partially inserted up to + /// TXTNODE_MAX void ReplaceText( const SwIndex& rStart, const xub_StrLen nDelLen, const XubString& rText ); void ReplaceTextOnly( xub_StrLen nPos, xub_StrLen nLen, const XubString& rText, diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx index 63a2c01..4bc16af 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -3322,11 +3322,23 @@ XubString SwTxtNode::GetRedlineTxt( xub_StrLen nIdx, xub_StrLen nLen, *************************************************************************/ void SwTxtNode::ReplaceText( const SwIndex& rStart, const xub_StrLen nDelLen, - const XubString& rText ) + const XubString& rStr) { OSL_ENSURE( rStart.GetIndex() < m_Text.Len() && rStart.GetIndex() + nDelLen <= m_Text.Len(), "SwTxtNode::ReplaceText: index out of bounds" ); + + ssize_t const nOverflow(static_cast<ssize_t>(m_Text.Len()) + + static_cast<ssize_t>(rStr.Len()) - nDelLen - TXTNODE_MAX); + SAL_WARN_IF(nOverflow > 0, "sw.core", + "SwTxtNode::ReplaceText: node text with insertion > TXTNODE_MAX."); + OUString const sInserted( + (nOverflow > 0) ? rStr.Copy(0, rStr.Len() - nOverflow) : rStr); + if (sInserted.isEmpty()) + { + return; + } + const xub_StrLen nStartPos = rStart.GetIndex(); xub_StrLen nEndPos = nStartPos + nDelLen; xub_StrLen nLen = nDelLen; @@ -3353,17 +3365,17 @@ void SwTxtNode::ReplaceText( const SwIndex& rStart, const xub_StrLen nDelLen, bool bOldExpFlg = IsIgnoreDontExpand(); SetIgnoreDontExpand( true ); - if( nLen && rText.Len() ) + if (nLen && sInserted.getLength()) { // dann das 1. Zeichen ersetzen den Rest loschen und einfuegen // Dadurch wird die Attributierung des 1. Zeichen expandiert! - m_Text.SetChar( nStartPos, rText.GetChar( 0 ) ); + m_Text.SetChar( nStartPos, sInserted[0] ); ++((SwIndex&)rStart); m_Text.Erase( rStart.GetIndex(), nLen - 1 ); Update( rStart, nLen - 1, true ); - XubString aTmpTxt( rText ); aTmpTxt.Erase( 0, 1 ); + XubString aTmpTxt(sInserted); aTmpTxt.Erase( 0, 1 ); m_Text.Insert( aTmpTxt, rStart.GetIndex() ); Update( rStart, aTmpTxt.Len(), false ); } @@ -3372,15 +3384,15 @@ void SwTxtNode::ReplaceText( const SwIndex& rStart, const xub_StrLen nDelLen, m_Text.Erase( nStartPos, nLen ); Update( rStart, nLen, true ); - m_Text.Insert( rText, nStartPos ); - Update( rStart, rText.Len(), false ); + m_Text.Insert( sInserted, nStartPos ); + Update( rStart, sInserted.getLength(), false ); } SetIgnoreDontExpand( bOldExpFlg ); SwDelTxt aDelHint( nStartPos, nDelLen ); NotifyClients( 0, &aDelHint ); - SwInsTxt aHint( nStartPos, rText.Len() ); + SwInsTxt aHint( nStartPos, sInserted.getLength() ); NotifyClients( 0, &aHint ); } diff --git a/sw/source/core/undo/unins.cxx b/sw/source/core/undo/unins.cxx index 4a0e67f..ac49017 100644 --- a/sw/source/core/undo/unins.cxx +++ b/sw/source/core/undo/unins.cxx @@ -672,11 +672,7 @@ void SwUndoReplace::Impl::UndoImpl(::sw::UndoRedoContext & rContext) } SwIndex aIdx( pNd, m_nSttCnt ); - if( m_nSttNd == m_nEndNd ) - { - pNd->EraseText( aIdx, sal_uInt16( m_sIns.getLength() ) ); - } - else + // don't look at m_sIns for deletion, maybe it was not completely inserted { rPam.GetPoint()->nNode = *pNd; rPam.GetPoint()->nContent.Assign( pNd, m_nSttCnt ); @@ -783,13 +779,9 @@ void SwUndoReplace::Impl::RedoImpl(::sw::UndoRedoContext & rContext) void SwUndoReplace::Impl::SetEnd(SwPaM const& rPam) { - if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode ) - { - // multiple paragraphs were inserted - const SwPosition* pEnd = rPam.End(); - m_nEndNd = m_nOffset + pEnd->nNode.GetIndex(); - m_nEndCnt = pEnd->nContent.GetIndex(); - } + const SwPosition* pEnd = rPam.End(); + m_nEndNd = m_nOffset + pEnd->nNode.GetIndex(); + m_nEndCnt = pEnd->nContent.GetIndex(); } commit d47218d79a2440e71efb66b2224063801ba6623b Author: Michael Stahl <[email protected]> Date: Fri Feb 15 13:29:04 2013 +0100 fdo#60732: make callers of SwTxtNode::InsertText more robust: Return the actually inserted string from InsertText(), so callers can check if the insertion was actually successful. Especially InsertHint() will likely cause problems if it cannot insert its CH_TXTATR; also Undo objects should not Undo more than was actually inserted. Change-Id: I87c9ea8b226ae4a2a6c20c112da76db07051a1bf diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index 4b78cd9..0c48f64 100644 --- a/sw/inc/ndtxt.hxx +++ b/sw/inc/ndtxt.hxx @@ -244,7 +244,10 @@ public: virtual sal_uInt16 ResetAllAttr(); /// insert text content - void InsertText( const XubString & rStr, const SwIndex & rIdx, + /// @param rStr text to insert; in case it does not fit into the limit of + /// TXTNODE_MAX, the longest prefix that fits is inserted + /// @return the prefix of rStr that was actually inserted + OUString InsertText( const XubString & rStr, const SwIndex & rIdx, const enum IDocumentContentOperations::InsertFlags nMode = IDocumentContentOperations::INS_DEFAULT ); diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx index b9bc7d2..c5879f4 100644 --- a/sw/source/core/doc/doc.cxx +++ b/sw/source/core/doc/doc.cxx @@ -945,12 +945,11 @@ bool SwDoc::InsertString( const SwPaM &rRg, const String &rStr, if (!bDoesUndo || !GetIDocumentUndoRedo().DoesGroupUndo()) { - pNode->InsertText( rStr, rPos.nContent, nInsertMode ); - + OUString const ins(pNode->InsertText(rStr, rPos.nContent, nInsertMode)); if (bDoesUndo) { - SwUndoInsert * const pUndo( new SwUndoInsert( - rPos.nNode, rPos.nContent.GetIndex(), rStr.Len(), nInsertMode)); + SwUndoInsert * const pUndo( new SwUndoInsert(rPos.nNode, + rPos.nContent.GetIndex(), ins.getLength(), nInsertMode)); GetIDocumentUndoRedo().AppendUndo(pUndo); } } @@ -980,16 +979,16 @@ bool SwDoc::InsertString( const SwPaM &rRg, const String &rStr, GetIDocumentUndoRedo().AppendUndo( pUndo ); } - pNode->InsertText( rStr, rPos.nContent, nInsertMode ); + OUString const ins(pNode->InsertText(rStr, rPos.nContent, nInsertMode)); - for( xub_StrLen i = 0; i < rStr.Len(); ++i ) + for (sal_Int32 i = 0; i < ins.getLength(); ++i) { nInsPos++; - // if CanGrouping() returns sal_True, everything has already been done - if( !pUndo->CanGrouping( rStr.GetChar( i ) )) + // if CanGrouping() returns true, everything has already been done + if (!pUndo->CanGrouping(ins[i])) { - pUndo = new SwUndoInsert( rPos.nNode, nInsPos, 1, nInsertMode, - !rCC.isLetterNumeric( rStr, i ) ); + pUndo = new SwUndoInsert(rPos.nNode, nInsPos, 1, nInsertMode, + !rCC.isLetterNumeric(ins, i)); GetIDocumentUndoRedo().AppendUndo( pUndo ); } } diff --git a/sw/source/core/doc/docedt.cxx b/sw/source/core/doc/docedt.cxx index 8859efb..539ebf4 100644 --- a/sw/source/core/doc/docedt.cxx +++ b/sw/source/core/doc/docedt.cxx @@ -716,8 +716,11 @@ bool SwDoc::Overwrite( const SwPaM &rRg, const String &rStr ) } SwTxtNode *pNode = rPt.nNode.GetNode().GetTxtNode(); - if(!pNode) + if (!pNode || ( static_cast<size_t>(rStr.Len()) // worst case: no erase + + static_cast<size_t>(pNode->GetTxt().Len()) > TXTNODE_MAX)) + { return sal_False; + } if (GetIDocumentUndoRedo().DoesUndo()) { diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx index 0fa7087..63a2c01 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -1703,23 +1703,27 @@ void SwTxtNode::CopyText( SwTxtNode *const pDest, } -void SwTxtNode::InsertText( const XubString & rStr, const SwIndex & rIdx, +OUString SwTxtNode::InsertText( const XubString & rStr, const SwIndex & rIdx, const IDocumentContentOperations::InsertFlags nMode ) { OSL_ENSURE( rIdx <= m_Text.Len(), "SwTxtNode::InsertText: invalid index." ); - OSL_ENSURE( (sal_uLong)m_Text.Len() + (sal_uLong)rStr.Len() <= STRING_LEN, - "SwTxtNode::InsertText: node text with insertion > STRING_LEN." ); xub_StrLen aPos = rIdx.GetIndex(); xub_StrLen nLen = m_Text.Len() - aPos; ssize_t const nOverflow(static_cast<ssize_t>(m_Text.Len()) + static_cast<ssize_t>(rStr.Len()) - TXTNODE_MAX); - m_Text.Insert((nOverflow > 0) ? rStr.Copy(0, rStr.Len() - nOverflow) : rStr, - aPos); + SAL_WARN_IF(nOverflow > 0, "sw.core", + "SwTxtNode::InsertText: node text with insertion > TXTNODE_MAX."); + OUString const sInserted( + (nOverflow > 0) ? rStr.Copy(0, rStr.Len() - nOverflow) : rStr); + if (sInserted.isEmpty()) + { + return sInserted; + } + m_Text.Insert(sInserted, aPos); assert(m_Text.Len() <= TXTNODE_MAX); nLen = m_Text.Len() - aPos - nLen; - - if ( !nLen ) return; + assert(nLen != 0); bool bOldExpFlg = IsIgnoreDontExpand(); if (nMode & IDocumentContentOperations::INS_FORCEHINTEXPAND) @@ -1804,6 +1808,7 @@ void SwTxtNode::InsertText( const XubString & rStr, const SwIndex & rIdx, SetCalcHiddenCharFlags(); CHECK_SWPHINTS(this); + return sInserted; } /************************************************************************* @@ -3007,9 +3012,12 @@ sal_Bool SwTxtNode::GetExpandTxt( SwTxtNode& rDestNd, const SwIndex* pDestIdx, if( aExpand.Len() ) { ++aDestIdx; // dahinter einfuegen; - rDestNd.InsertText( aExpand, aDestIdx ); + OUString const ins( + rDestNd.InsertText( aExpand, aDestIdx)); + SAL_INFO_IF(ins.getLength() != aExpand.Len(), + "sw.core", "GetExpandTxt lossage"); aDestIdx = nInsPos + nAttrStartIdx; - nInsPos = nInsPos + aExpand.Len(); + nInsPos = nInsPos + ins.getLength(); } rDestNd.EraseText( aDestIdx, 1 ); --nInsPos; @@ -3038,10 +3046,13 @@ sal_Bool SwTxtNode::GetExpandTxt( SwTxtNode& rDestNd, const SwIndex* pDestIdx, rDestNd.InsertItem(aItem, aDestIdx.GetIndex(), aDestIdx.GetIndex() ); - rDestNd.InsertText( sExpand, aDestIdx, - IDocumentContentOperations::INS_EMPTYEXPAND); + OUString const ins( rDestNd.InsertText(sExpand, + aDestIdx, + IDocumentContentOperations::INS_EMPTYEXPAND)); + SAL_INFO_IF(ins.getLength() != sExpand.Len(), + "sw.core", "GetExpandTxt lossage"); aDestIdx = nInsPos + nAttrStartIdx; - nInsPos = nInsPos + sExpand.Len(); + nInsPos = nInsPos + ins.getLength(); } } rDestNd.EraseText( aDestIdx, 1 ); diff --git a/sw/source/core/txtnode/thints.cxx b/sw/source/core/txtnode/thints.cxx index 6f66720..e133f45 100644 --- a/sw/source/core/txtnode/thints.cxx +++ b/sw/source/core/txtnode/thints.cxx @@ -1254,7 +1254,15 @@ bool SwTxtNode::InsertHint( SwTxtAttr * const pAttr, const SetAttrMode nMode ) SwIndex aIdx( this, *pAttr->GetStart() ); const rtl::OUString c(GetCharOfTxtAttr(*pAttr)); - InsertText( c, aIdx, nInsertFlags ); + OUString const ins( InsertText(c, aIdx, nInsertFlags) ); + if (ins.isEmpty()) + { + // do not record deletion of Format! + ::sw::UndoGuard const ug( + pFmt->GetDoc()->GetIDocumentUndoRedo()); + DestroyAttr(pAttr); + return false; // text node full :( + } nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR; if (pAnchor && @@ -1371,7 +1379,12 @@ bool SwTxtNode::InsertHint( SwTxtAttr * const pAttr, const SetAttrMode nMode ) // Dokument nicht eingetrage wird. SwIndex aNdIdx( this, *pAttr->GetStart() ); const rtl::OUString c(GetCharOfTxtAttr(*pAttr)); - InsertText( c, aNdIdx, nInsertFlags ); + OUString const ins( InsertText(c, aNdIdx, nInsertFlags) ); + if (ins.isEmpty()) + { + DestroyAttr(pAttr); + return false; // text node full :( + } nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR; } @@ -1430,7 +1443,13 @@ bool SwTxtNode::InsertHint( SwTxtAttr * const pAttr, const SetAttrMode nMode ) if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) ) { SwIndex aIdx( this, *pAttr->GetStart() ); - InsertText( rtl::OUString(GetCharOfTxtAttr(*pAttr)), aIdx, nInsertFlags ); + OUString const ins( InsertText(OUString(GetCharOfTxtAttr(*pAttr)), + aIdx, nInsertFlags) ); + if (ins.isEmpty()) + { + DestroyAttr(pAttr); + return false; // text node full :( + } // adjust end of hint to account for inserted CH_TXTATR xub_StrLen * const pEnd(pAttr->GetEnd()); diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx index fc62fcd..f824b8e 100644 --- a/sw/source/core/undo/undel.cxx +++ b/sw/source/core/undo/undel.cxx @@ -789,8 +789,9 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext) } if( pTxtNd ) { - pTxtNd->InsertText( *pEndStr, aPos.nContent, - IDocumentContentOperations::INS_NOHINTEXPAND ); + OUString const ins( pTxtNd->InsertText(*pEndStr, aPos.nContent, + IDocumentContentOperations::INS_NOHINTEXPAND) ); + assert(ins.getLength() == pEndStr->Len()); // must succeed // METADATA: restore pTxtNd->RestoreMetadata(m_pMetadataUndoEnd); } @@ -882,8 +883,9 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext) // SectionNode mode and selection from top to bottom: // -> in StartNode is still the rest of the Join => delete aPos.nContent.Assign( pTxtNd, nSttCntnt ); - pTxtNd->InsertText( *pSttStr, aPos.nContent, - IDocumentContentOperations::INS_NOHINTEXPAND ); + OUString const ins( pTxtNd->InsertText(*pSttStr, aPos.nContent, + IDocumentContentOperations::INS_NOHINTEXPAND) ); + assert(ins.getLength() == pSttStr->Len()); // must succeed // METADATA: restore pTxtNd->RestoreMetadata(m_pMetadataUndoStart); } diff --git a/sw/source/core/undo/unins.cxx b/sw/source/core/undo/unins.cxx index 473a915..4a0e67f 100644 --- a/sw/source/core/undo/unins.cxx +++ b/sw/source/core/undo/unins.cxx @@ -340,8 +340,10 @@ void SwUndoInsert::RedoImpl(::sw::UndoRedoContext & rContext) { SwTxtNode *const pTxtNode = pCNd->GetTxtNode(); OSL_ENSURE( pTxtNode, "where is my textnode ?" ); - pTxtNode->InsertText( *pTxt, pPam->GetMark()->nContent, - m_nInsertFlags ); + OUString const ins( + pTxtNode->InsertText( *pTxt, pPam->GetMark()->nContent, + m_nInsertFlags) ); + assert(ins.getLength() == pTxt->Len()); // must succeed DELETEZ( pTxt ); } else @@ -704,7 +706,8 @@ void SwUndoReplace::Impl::UndoImpl(::sw::UndoRedoContext & rContext) if (!m_sOld.isEmpty()) { - pNd->InsertText( m_sOld, aIdx ); + OUString const ins( pNd->InsertText( m_sOld, aIdx ) ); + assert(ins.getLength() == m_sOld.getLength()); // must succeed } if( pHistory ) diff --git a/sw/source/core/undo/unovwr.cxx b/sw/source/core/undo/unovwr.cxx index b242426..3cc6c4d 100644 --- a/sw/source/core/undo/unovwr.cxx +++ b/sw/source/core/undo/unovwr.cxx @@ -154,8 +154,9 @@ sal_Bool SwUndoOverwrite::CanGrouping( SwDoc* pDoc, SwPosition& rPos, bool bOldExpFlg = pDelTxtNd->IsIgnoreDontExpand(); pDelTxtNd->SetIgnoreDontExpand( true ); - pDelTxtNd->InsertText( rtl::OUString(cIns), rPos.nContent, - IDocumentContentOperations::INS_EMPTYEXPAND ); + OUString const ins( pDelTxtNd->InsertText(OUString(cIns), rPos.nContent, + IDocumentContentOperations::INS_EMPTYEXPAND) ); + assert(ins.getLength() == 1); // check in SwDoc::Overwrite => cannot fail aInsStr.Insert( cIns ); if( !bInsChar ) @@ -210,7 +211,8 @@ void SwUndoOverwrite::UndoImpl(::sw::UndoRedoContext & rContext) { // do it individually, to keep the attributes! *pTmpStr = aDelStr.GetChar( n ); - pTxtNd->InsertText( aTmpStr, rIdx /*???, SETATTR_NOTXTATRCHR*/ ); + OUString const ins( pTxtNd->InsertText(aTmpStr, rIdx) ); + assert(ins.getLength() == 1); // cannot fail rIdx -= 2; pTxtNd->EraseText( rIdx, 1 ); rIdx += 2; @@ -279,8 +281,10 @@ void SwUndoOverwrite::RedoImpl(::sw::UndoRedoContext & rContext) for( xub_StrLen n = 0; n < aInsStr.Len(); n++ ) { // do it individually, to keep the attributes! - pTxtNd->InsertText( rtl::OUString(aInsStr.GetChar(n)), rIdx, - IDocumentContentOperations::INS_EMPTYEXPAND ); + OUString const ins( + pTxtNd->InsertText( rtl::OUString(aInsStr.GetChar(n)), rIdx, + IDocumentContentOperations::INS_EMPTYEXPAND) ); + assert(ins.getLength() == 1); // cannot fail if( n < aDelStr.Len() ) { rIdx -= 2; commit 447bb5b5006051672ec526b75bec7db02d2db82e Author: Michael Stahl <[email protected]> Date: Thu Feb 14 23:34:16 2013 +0100 SwDoc::Overwrite: probably a bad idea to overwrite fieldmarks Change-Id: Iba94df67c21514cf4f5361bab28629c6d5d9d3e8 diff --git a/sw/source/core/doc/docedt.cxx b/sw/source/core/doc/docedt.cxx index 4ec41ac..8859efb 100644 --- a/sw/source/core/doc/docedt.cxx +++ b/sw/source/core/doc/docedt.cxx @@ -131,8 +131,18 @@ typedef boost::ptr_vector< _SaveRedline > _SaveRedlines; static bool lcl_MayOverwrite( const SwTxtNode *pNode, const xub_StrLen nPos ) { sal_Unicode cChr = pNode->GetTxt().GetChar( nPos ); - return !( ( CH_TXTATR_BREAKWORD == cChr || CH_TXTATR_INWORD == cChr ) && - (0 != pNode->GetTxtAttrForCharAt( nPos ) ) ); + switch (cChr) + { + case CH_TXTATR_BREAKWORD: + case CH_TXTATR_INWORD: + return !pNode->GetTxtAttrForCharAt(nPos);// how could there be none? + case CH_TXT_ATR_FIELDSTART: + case CH_TXT_ATR_FIELDEND: + case CH_TXT_ATR_FORMELEMENT: + return false; + default: + return true; + } } static void lcl_SkipAttr( const SwTxtNode *pNode, SwIndex &rIdx, xub_StrLen &rStart ) commit 5a80c24b145c8efe0dd384ef88e7d31173522fb8 Author: Michael Stahl <[email protected]> Date: Thu Feb 14 23:02:35 2013 +0100 sw: do not crash when it's not possible to insert fly Change-Id: Idfcf54013107ba6b7ce3de0d0bddbef306698f33 diff --git a/sw/source/core/doc/doclay.cxx b/sw/source/core/doc/doclay.cxx index f73cc72..b97a263 100644 --- a/sw/source/core/doc/doclay.cxx +++ b/sw/source/core/doc/doclay.cxx @@ -654,7 +654,11 @@ SwFlyFrmFmt* SwDoc::_MakeFlySection( const SwPosition& rAnchPos, if (pTxtNode != NULL) { SwFmtFlyCnt aFmt( pFmt ); - pTxtNode->InsertItem( aFmt, nStt, nStt ); + bool const bSuccess( pTxtNode->InsertItem(aFmt, nStt, nStt) ); + if (!bSuccess) // may fail if there's no space left or header/ftr + { // pFmt is dead now + return 0; + } } } @@ -740,7 +744,9 @@ SwFlyFrmFmt* SwDoc::MakeFlySection( RndStdIds eAnchorType, if (bCalledFromShell && !lcl_IsItemSet(*pNewTxtNd, RES_PARATR_ADJUST) && SFX_ITEM_SET == pAnchorNode->GetSwAttrSet(). GetItemState(RES_PARATR_ADJUST, sal_True, &pItem)) + { static_cast<SwCntntNode *>(pNewTxtNd)->SetAttr(*pItem); + } pFmt = _MakeFlySection( *pAnchorPos, *pNewTxtNd, eAnchorType, pFlySet, pFrmFmt ); @@ -941,8 +947,13 @@ SwDrawFrmFmt* SwDoc::Insert( const SwPaM &rRg, { xub_StrLen nStt = rRg.GetPoint()->nContent.GetIndex(); SwFmtFlyCnt aFmt( pFmt ); - rRg.GetPoint()->nNode.GetNode().GetTxtNode()->InsertItem( - aFmt, nStt, nStt ); + bool const bSuccess( // may fail if there's no space left + rRg.GetPoint()->nNode.GetNode().GetTxtNode()->InsertItem( + aFmt, nStt, nStt)); + if (!bSuccess) + { // pFmt is dead now + return 0; + } } SwDrawContact* pContact = new SwDrawContact( pFmt, &rDrawObj ); commit 549c0f785d4b6d4bc1b39b22827d77d66f48430a Author: Michael Stahl <[email protected]> Date: Thu Feb 14 19:27:28 2013 +0100 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 diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index 5a47fb2..4b78cd9 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 a972611..61a720f 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<const SwTxtNode&>(rPrev).GetTxt().Len() + + static_cast<const SwTxtNode&>(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<const SwTxtNode*>(this); - sal_uInt64 nSum = pTxtNd->GetTxt().Len(); - pTxtNd = static_cast<const SwTxtNode*>(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 aff2753..0fa7087 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<ssize_t>(m_Text.Len()) + + static_cast<ssize_t>(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; _______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
