[Libreoffice-commits] core.git: 7 commits - sw/inc sw/source

Michael Stahl mstahl at redhat.com
Fri Feb 15 13:46:58 PST 2013


 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 <mstahl at redhat.com>
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 <mstahl at redhat.com>
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 <mstahl at redhat.com>
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 <mstahl at redhat.com>
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 <mstahl at redhat.com>
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 <mstahl at redhat.com>
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 <mstahl at redhat.com>
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;


More information about the Libreoffice-commits mailing list