sc/qa/unit/data/ods/tdf170963_row_breaks.ods |binary sc/qa/unit/subsequent_export_test5.cxx | 14 ++++++++++++++ sc/source/filter/excel/xepage.cxx | 14 +++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-)
New commits: commit 63542204016d8f15db4d992ee298037a544b67e2 Author: Aron Budea <[email protected]> AuthorDate: Mon Feb 23 04:50:25 2026 +1030 Commit: Aron Budea <[email protected]> CommitDate: Fri Feb 27 03:30:51 2026 +0100 tdf#170963 sc: limit row/colBreaks in XLSX export to what Excel can handle The number of rowBreaks/colBreaks is practically limited to 1023 in Excel, as described in Part 1 Sections 18.3.1.14 and 18.3.1.74 in [MS-OI29500]. Don't export more than the limit. Change-Id: I45e49705022b90ab5b3b404bfc5d07da183e0db1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199999 Reviewed-by: Aron Budea <[email protected]> Tested-by: Jenkins diff --git a/sc/qa/unit/data/ods/tdf170963_row_breaks.ods b/sc/qa/unit/data/ods/tdf170963_row_breaks.ods new file mode 100644 index 000000000000..ac8befdc7f67 Binary files /dev/null and b/sc/qa/unit/data/ods/tdf170963_row_breaks.ods differ diff --git a/sc/qa/unit/subsequent_export_test5.cxx b/sc/qa/unit/subsequent_export_test5.cxx index 983b50782898..9d65ce41bf07 100644 --- a/sc/qa/unit/subsequent_export_test5.cxx +++ b/sc/qa/unit/subsequent_export_test5.cxx @@ -1453,6 +1453,20 @@ CPPUNIT_TEST_FIXTURE(ScExportTest5, testTdf170565_empty_functions) assertXPathContent(pSheet, "/x:worksheet/x:sheetData/x:row[6]/x:c[2]/x:f", u"PRODUCT(,)"); } +CPPUNIT_TEST_FIXTURE(ScExportTest5, testTdf170963_row_breaks) +{ + createScDoc("ods/tdf170963_row_breaks.ods"); + save(TestFilter::XLSX); + + xmlDocUniquePtr pSheet = parseExport(u"xl/worksheets/sheet1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + const int nMaxRowBreaks = 1023; + // Original had 1026 row breaks, but the max Excel handles is 1023 + // Without the fix all 1026 got exported + assertXPath(pSheet, "/x:worksheet/x:rowBreaks", "count", OUString::number(nMaxRowBreaks)); + CPPUNIT_ASSERT_EQUAL(nMaxRowBreaks, countXPathNodes(pSheet, "/x:worksheet/x:rowBreaks/x:brk")); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/excel/xepage.cxx b/sc/source/filter/excel/xepage.cxx index 42a579229ec1..dad649ab7256 100644 --- a/sc/source/filter/excel/xepage.cxx +++ b/sc/source/filter/excel/xepage.cxx @@ -200,14 +200,22 @@ void XclExpPageBreaks::SaveXml( XclExpXmlStream& rStrm ) sal_Int32 nElement = GetRecId() == EXC_ID_HORPAGEBREAKS ? XML_rowBreaks : XML_colBreaks; sax_fastparser::FSHelperPtr& pWorksheet = rStrm.GetCurrentStream(); - OString sNumPageBreaks = OString::number( mrPageBreaks.size() ); + // According to Part 1 Sections 18.3.1.14 and 18.3.1.74 in [MS-OI29500], the practical + // limit is 1023 + const size_t nMaxPageBreaks = static_cast< size_t >( 1023 ); + const size_t nNumPageBreaks = std::min( nMaxPageBreaks, mrPageBreaks.size() ); + OString sNumPageBreaks = OString::number( nNumPageBreaks ); + SAL_WARN_IF( nNumPageBreaks < mrPageBreaks.size(), "sc.filter", + "Number of page breaks exceeds Office implementation maximum, limiting them to " + + sNumPageBreaks + " and discarding the rest (total no. was " + + OString::number(mrPageBreaks.size()) + ")" ); pWorksheet->startElement( nElement, XML_count, sNumPageBreaks, XML_manualBreakCount, sNumPageBreaks ); - for( const auto& rPageBreak : mrPageBreaks ) + for( size_t nBreak = 0; nBreak < nNumPageBreaks; nBreak++ ) { pWorksheet->singleElement( XML_brk, - XML_id, OString::number(rPageBreak), + XML_id, OString::number(mrPageBreaks[nBreak]), XML_man, "true", XML_max, OString::number(mnMaxPos), XML_min, "0"
