sc/qa/unit/subsequent_export_test4.cxx | 76 +++++++++++++++++++++++++++++++++ sc/source/filter/excel/xecontent.cxx | 5 +- 2 files changed, 80 insertions(+), 1 deletion(-)
New commits: commit f41c58ad4172729a2be261f0ccea01d741d61a2d Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Fri Aug 22 21:36:55 2025 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Fri Aug 22 21:30:47 2025 +0200 tdf#150229: increase maximum size of URLs for Excel file formats export The values (8192 characters for XLSX, 2083 characters for XLS) are from experiments. While 8192 looks legit, 2083 seems odd - but when I export an XLSX with 2084-character hyperlink to XLS, the end result misses the hyperlink completely. Change-Id: Iaf607063b624af93393609eb42feba62910d5254 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190078 Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Tested-by: Jenkins diff --git a/sc/qa/unit/subsequent_export_test4.cxx b/sc/qa/unit/subsequent_export_test4.cxx index b1a90b9f7517..9c0b90124e34 100644 --- a/sc/qa/unit/subsequent_export_test4.cxx +++ b/sc/qa/unit/subsequent_export_test4.cxx @@ -52,8 +52,12 @@ #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> #include <com/sun/star/packages/zip/ZipFileAccess.hpp> #include <com/sun/star/sheet/GlobalSheetSettings.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/text/XText.hpp> #include <com/sun/star/text/XTextColumns.hpp> +#include <com/sun/star/text/XTextFieldsSupplier.hpp> using namespace ::com::sun::star; using namespace ::com::sun::star::uno; @@ -2244,6 +2248,78 @@ CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf108244) CPPUNIT_ASSERT_EQUAL(u"1"_ustr, getXPathContent(pXmlDoc, "count(//office:annotation)")); } +CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf150229) +{ + // Create a long URL: longer than Excel allows + OUString longUrl = []() { + OUStringBuffer buf("https://www.example.org/query?foo&bar&baz="); + while (buf.getLength() < 8200) + buf.append("0123456789"); + return buf.makeStringAndClear(); + }(); + + // Create a document, and put that URL as hyperlink into a cell + + createScDoc(); + + { + auto xDoc = mxComponent.queryThrow<sheet::XSpreadsheetDocument>(); + auto xSheets = xDoc->getSheets().queryThrow<container::XIndexAccess>(); + auto xSheet = xSheets->getByIndex(0).queryThrow<sheet::XSpreadsheet>(); + auto xCell = xSheet->getCellByPosition(0, 0).queryThrow<text::XText>(); + + auto xFactory = mxComponent.queryThrow<lang::XMultiServiceFactory>(); + auto xField = xFactory->createInstance(u"com.sun.star.text.TextField.URL"_ustr) + .queryThrow<beans::XPropertySet>(); + xField->setPropertyValue(u"URL"_ustr, uno::Any(longUrl)); + xField->setPropertyValue(u"Representation"_ustr, uno::Any(u"hyperlink"_ustr)); + + xCell->insertTextContent(xCell->createTextCursor(), xField.queryThrow<text::XTextContent>(), + false); + } + + // Test XLSX export: the hyperlink must truncate at 8192 character boundary + + saveAndReload(u"Calc Office Open XML"_ustr); + + { + auto xDoc = mxComponent.queryThrow<sheet::XSpreadsheetDocument>(); + auto xSheets = xDoc->getSheets().queryThrow<container::XIndexAccess>(); + auto xSheet = xSheets->getByIndex(0).queryThrow<sheet::XSpreadsheet>(); + auto xCell = xSheet->getCellByPosition(0, 0).queryThrow<text::XText>(); + CPPUNIT_ASSERT_EQUAL(u"hyperlink"_ustr, xCell->getString()); + auto xCellFieldsSupplier = xCell.queryThrow<text::XTextFieldsSupplier>(); + auto xFields = xCellFieldsSupplier->getTextFields()->createEnumeration(); + auto xField = xFields->nextElement().queryThrow<beans::XPropertySet>(); + CPPUNIT_ASSERT_EQUAL(longUrl.copy(0, 8192), + xField->getPropertyValue(u"URL"_ustr).get<OUString>()); + } + + // Test the respective OOXML markyp + + xmlDocUniquePtr pXml = parseExport(u"xl/worksheets/_rels/sheet1.xml.rels"_ustr); + CPPUNIT_ASSERT(pXml); + assertXPath(pXml, "//rels:Relationship", "Target", longUrl.subView(0, 8192)); + + // Test XLS export: the hyperlink must truncate at 2083 character boundary (that's the limit + // I found experimentally) + + saveAndReload(u"MS Excel 97"_ustr); + + { + auto xDoc = mxComponent.queryThrow<sheet::XSpreadsheetDocument>(); + auto xSheets = xDoc->getSheets().queryThrow<container::XIndexAccess>(); + auto xSheet = xSheets->getByIndex(0).queryThrow<sheet::XSpreadsheet>(); + auto xCell = xSheet->getCellByPosition(0, 0).queryThrow<text::XText>(); + CPPUNIT_ASSERT_EQUAL(u"hyperlink"_ustr, xCell->getString()); + auto xCellFieldsSupplier = xCell.queryThrow<text::XTextFieldsSupplier>(); + auto xFields = xCellFieldsSupplier->getTextFields()->createEnumeration(); + auto xField = xFields->nextElement().queryThrow<beans::XPropertySet>(); + CPPUNIT_ASSERT_EQUAL(longUrl.copy(0, 2083), + xField->getPropertyValue(u"URL"_ustr).get<OUString>()); + } +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/excel/xecontent.cxx b/sc/source/filter/excel/xecontent.cxx index 413094f44adb..c2da396ea972 100644 --- a/sc/source/filter/excel/xecontent.cxx +++ b/sc/source/filter/excel/xecontent.cxx @@ -406,7 +406,10 @@ XclExpHyperlink::XclExpHyperlink( const XclExpRoot& rRoot, const SvxURLField& rU } else if( eProtocol != INetProtocol::NotValid ) { - XclExpString aUrl( aUrlObj.GetURLNoMark(), XclStrFlags::ForceUnicode, 255 ); + // There is an undocumented limitation of 8192 characters for XLSX hyperlink length; and + // one more for XLS format, which is a strange number 2083; both found by experimentation: + const sal_uInt16 nMaxLen = rRoot.GetOutput() == EXC_OUTPUT_XML_2007 ? 8192 : 2083; + XclExpString aUrl(aUrlObj.GetURLNoMark(), XclStrFlags::ForceUnicode, nMaxLen); aXclStrm << XclTools::maGuidUrlMoniker << sal_uInt32( aUrl.GetBufferSize() + 2 ); // byte count + 1 trailing zero word aUrl.WriteBuffer( aXclStrm ); // NO flags