sw/qa/extras/ooxmlexport/data/tdf147810.odt |binary sw/qa/extras/ooxmlexport/ooxmlexport11.cxx | 6 ++ sw/source/filter/ww8/docxattributeoutput.cxx | 72 ++++++++++++++++++--------- sw/source/filter/ww8/docxattributeoutput.hxx | 3 - 4 files changed, 56 insertions(+), 25 deletions(-)
New commits: commit 23cb5a95e057060a47facad19ad150134aa0692b Author: Tünde Tóth <toth.tu...@nisz.hu> AuthorDate: Tue Mar 28 09:17:17 2023 +0200 Commit: László Németh <nem...@numbertext.org> CommitDate: Tue Apr 18 11:04:03 2023 +0200 tdf#147810 DOCX export: fix corrupt file with hyperlink and text box Remove m_startedHyperlink boolean, because the m_nHyperLinkCount is more precise in nested paragraphs, e.g. when exporting hyperlink combined with the export of the paragraph of a text box attached to the paragraph of the hyperlink, which caused corrupt DOCX file with data loss. Regression from commit 9835a5823e0f559aabbc0e15ea126c82229c4bc7 "sw textboxes: reimplement ODF import/export". Change-Id: I94bcb64a756ba2c90360629640f667190fa45f3a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149677 Tested-by: Jenkins Tested-by: László Németh <nem...@numbertext.org> Reviewed-by: László Németh <nem...@numbertext.org> diff --git a/sw/qa/extras/ooxmlexport/data/tdf147810.odt b/sw/qa/extras/ooxmlexport/data/tdf147810.odt new file mode 100644 index 000000000000..eb0d1a88466c Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf147810.odt differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx index 908d8db90e3e..4e8d2991d83b 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx @@ -889,6 +889,12 @@ DECLARE_OOXMLEXPORT_TEST(testGroupedShapeLink, "grouped_link.docx") getProperty<OUString>(xGroupShape->getByIndex(1), "Hyperlink")); } +DECLARE_OOXMLEXPORT_TEST(testTdf147810, "tdf147810.odt") +{ + // Without the accompanying fix in place, this test would have crashed, + // because the exported file was corrupted. +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 093ace109ddb..5590857f1c74 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -499,7 +499,7 @@ sal_Int32 DocxAttributeOutput::StartParagraph(ww8::WW8TableNodeInfo::Pointer_t p m_bParagraphOpened = true; m_bIsFirstParagraph = false; - m_nHyperLinkCount.push(0); + m_nHyperLinkCount.push_back(0); return nParaId; } @@ -1107,12 +1107,12 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT /* If m_nHyperLinkCount > 0 that means hyperlink tag is not yet closed. * This is due to nested hyperlink tags. So close it before end of paragraph. */ - if(m_nHyperLinkCount.top() > 0) + if(m_nHyperLinkCount.back() > 0) { - for(sal_Int32 nHyperLinkToClose = 0; nHyperLinkToClose < m_nHyperLinkCount.top(); ++nHyperLinkToClose) + for(sal_Int32 nHyperLinkToClose = 0; nHyperLinkToClose < m_nHyperLinkCount.back(); ++nHyperLinkToClose) m_pSerializer->endElementNS( XML_w, XML_hyperlink ); } - m_nHyperLinkCount.pop(); + m_nHyperLinkCount.pop_back(); if (m_aRunSdt.m_bStartedSdt) { @@ -1685,7 +1685,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In continue; } - if (m_startedHyperlink || m_pHyperlinkAttrList.is()) + if (m_nHyperLinkCount.back() > 0 || m_pHyperlinkAttrList.is()) { ++m_nFieldsInHyperlink; } @@ -1716,7 +1716,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In if ( m_closeHyperlinkInPreviousRun ) { - if ( m_startedHyperlink ) + if (m_nHyperLinkCount.back() > 0) { for ( int i = 0; i < nFieldsInPrevHyperlink; i++ ) { @@ -1726,11 +1726,24 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In m_Fields.pop_back(); } m_pSerializer->endElementNS( XML_w, XML_hyperlink ); - m_startedHyperlink = false; m_endPageRef = false; - m_nHyperLinkCount.top()--; + m_nHyperLinkCount.back()--; + m_closeHyperlinkInPreviousRun = false; + } + else + { + bool bIsStartedHyperlink = false; + for (const sal_Int32 nLinkCount : m_nHyperLinkCount) + { + if (nLinkCount > 0) + { + bIsStartedHyperlink = true; + break; + } + } + if (!bIsStartedHyperlink) + m_closeHyperlinkInPreviousRun = false; } - m_closeHyperlinkInPreviousRun = false; } // Write the hyperlink and toc fields starts @@ -1745,7 +1758,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In StartField_Impl( pNode, nPos, *pIt, true ); EndRedline( m_pRedlineData, bLastRun ); - if (m_startedHyperlink) + if (m_nHyperLinkCount.back() > 0) ++m_nFieldsInHyperlink; // Remove the field if no end needs to be written @@ -1805,8 +1818,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In newStartedHyperlink = true; m_pSerializer->startElementNS( XML_w, XML_hyperlink, detachFrom( m_pHyperlinkAttrList ) ); - m_startedHyperlink = true; - m_nHyperLinkCount.top()++; + m_nHyperLinkCount.back()++; } // if there is some redlining in the document, output it @@ -1820,7 +1832,8 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In DoWritePermissionsStart(); DoWriteAnnotationMarks(); - if( m_closeHyperlinkInThisRun && m_startedHyperlink && !m_hyperLinkAnchor.isEmpty() && m_hyperLinkAnchor.startsWith("_Toc")) + if (m_closeHyperlinkInThisRun && m_nHyperLinkCount.back() > 0 && !m_hyperLinkAnchor.isEmpty() + && m_hyperLinkAnchor.startsWith("_Toc")) { OUString sToken; m_pSerializer->startElementNS(XML_w, XML_r); @@ -1942,7 +1955,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In if ( m_closeHyperlinkInThisRun ) { - if ( m_startedHyperlink ) + if (m_nHyperLinkCount.back() > 0) { if( m_endPageRef ) { @@ -1967,10 +1980,23 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In m_nFieldsInHyperlink = 0; m_pSerializer->endElementNS( XML_w, XML_hyperlink ); - m_startedHyperlink = false; - m_nHyperLinkCount.top()--; + m_nHyperLinkCount.back()--; + m_closeHyperlinkInThisRun = false; + } + else + { + bool bIsStartedHyperlink = false; + for (const sal_Int32 nLinkCount : m_nHyperLinkCount) + { + if (nLinkCount > 0) + { + bIsStartedHyperlink = true; + break; + } + } + if (!bIsStartedHyperlink) + m_closeHyperlinkInThisRun = false; } - m_closeHyperlinkInThisRun = false; } if (!newStartedHyperlink) @@ -3793,7 +3819,8 @@ bool DocxAttributeOutput::StartURL( const OUString& rUrl, const OUString& rTarge bool DocxAttributeOutput::EndURL(bool const) { m_closeHyperlinkInThisRun = true; - if(m_startedHyperlink && !m_hyperLinkAnchor.isEmpty() && m_hyperLinkAnchor.startsWith("_Toc")) + if (m_nHyperLinkCount.back() > 0 && !m_hyperLinkAnchor.isEmpty() + && m_hyperLinkAnchor.startsWith("_Toc")) { m_endPageRef = true; } @@ -6330,8 +6357,8 @@ void DocxAttributeOutput::pushToTableExportContext(DocxTableExportContext& rCont rContext.m_bStartedRunSdt = m_aRunSdt.m_bStartedSdt; m_aRunSdt.m_bStartedSdt = false; - rContext.m_nHyperLinkCount = m_nHyperLinkCount.top(); - m_nHyperLinkCount.top() = 0; + rContext.m_nHyperLinkCount = m_nHyperLinkCount.back(); + m_nHyperLinkCount.back() = 0; } void DocxAttributeOutput::popFromTableExportContext(DocxTableExportContext const & rContext) @@ -6341,7 +6368,7 @@ void DocxAttributeOutput::popFromTableExportContext(DocxTableExportContext const m_tableReference.m_nTableDepth = rContext.m_nTableDepth; m_aParagraphSdt.m_bStartedSdt = rContext.m_bStartedParaSdt; m_aRunSdt.m_bStartedSdt = rContext.m_bStartedRunSdt; - m_nHyperLinkCount.top() = rContext.m_nHyperLinkCount; + m_nHyperLinkCount.back() = rContext.m_nHyperLinkCount; } void DocxAttributeOutput::WriteTextBox(uno::Reference<drawing::XShape> xShape) @@ -9974,7 +10001,6 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, const FSHelperPtr m_nTextFrameLevel( 0 ), m_closeHyperlinkInThisRun( false ), m_closeHyperlinkInPreviousRun( false ), - m_startedHyperlink( false ), m_nFieldsInHyperlink( 0 ), m_bExportingOutline(false), m_nChartCount(0), @@ -9990,7 +10016,7 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, const FSHelperPtr m_nParaAfterSpacing(0) , m_nStateOfFlyFrame( FLY_NOT_PROCESSED ) { - m_nHyperLinkCount.push(0); + m_nHyperLinkCount.push_back(0); } DocxAttributeOutput::~DocxAttributeOutput() diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index bf2af19a410e..5b4708936605 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -952,9 +952,8 @@ private: // close of hyperlink needed bool m_closeHyperlinkInThisRun; bool m_closeHyperlinkInPreviousRun; - bool m_startedHyperlink; // Count nested HyperLinks - std::stack<sal_Int32> m_nHyperLinkCount; + std::vector<sal_Int32> m_nHyperLinkCount; sal_Int16 m_nFieldsInHyperlink; // If the exported numbering rule defines the outlines