From cb2bc2ba0e39867a270c6978d99c9d87bcf99c62 Mon Sep 17 00:00:00 2001 From: Ujjawal Kumar Date: Mon, 30 Mar 2026 17:22:12 +0530 Subject: [PATCH] WordML import: fix huge recursion depth in replace-spaces Bug document: fdo67478-1.doc The replace-spaces template consumed one pair of spaces per recursion level. WordML documents with very long space runs (e.g. 61000 consecutive spaces) exceeded libxslt's 3000 depth limit, causing an import error. Consume the entire consecutive space run in a single call by using translate() to find the first non-space character, counting all leading spaces at once, and emitting a single element. Recursion depth is now bounded by the number of separate space runs, not the total number of spaces. Change-Id: Ifb11a61a2e89274684e1d6d38920c8792598fa43 Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/62 Reviewed-by: Michael Stahl Tested-by: Jenkins CPCI (cherry picked from commit 7ba970bce9e1200e5712afe76ec3a85056be9263) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/204666 Tested-by: Jenkins Reviewed-by: Xisco Fauli --- .../xslt/import/wordml/wordml2ooo_text.xsl | 46 ++++++++----- solenv/clang-format/excludelist | 1 + sw/CppunitTest_sw_xsltimport.mk | 65 +++++++++++++++++++ sw/Module_sw.mk | 1 + .../xsltimport/data/testReplaceSpaces.xslt | 1 + sw/qa/extras/xsltimport/xsltimport.cxx | 35 ++++++++++ 6 files changed, 134 insertions(+), 15 deletions(-) create mode 100644 sw/CppunitTest_sw_xsltimport.mk create mode 100644 sw/qa/extras/xsltimport/data/testReplaceSpaces.xslt create mode 100644 sw/qa/extras/xsltimport/xsltimport.cxx diff --git a/filter/source/xslt/import/wordml/wordml2ooo_text.xsl b/filter/source/xslt/import/wordml/wordml2ooo_text.xsl index e2b94b3ec51f..d147629cb63a 100644 --- a/filter/source/xslt/import/wordml/wordml2ooo_text.xsl +++ b/filter/source/xslt/import/wordml/wordml2ooo_text.xsl @@ -1001,21 +1001,37 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist index b3c4b8220397..20b050c8a1b5 100644 --- a/solenv/clang-format/excludelist +++ b/solenv/clang-format/excludelist @@ -11846,6 +11846,7 @@ sw/qa/extras/ww8export/ww8export2.cxx sw/qa/extras/ww8export/ww8export3.cxx sw/qa/extras/ww8export/ww8export4.cxx sw/qa/extras/ww8import/ww8import.cxx +sw/qa/extras/xsltimport/xsltimport.cxx sw/qa/inc/bordertest.hxx sw/qa/inc/swmodeltestbase.hxx sw/qa/unit/sw-dialogs-test.cxx diff --git a/sw/CppunitTest_sw_xsltimport.mk b/sw/CppunitTest_sw_xsltimport.mk new file mode 100644 index 000000000000..33c9f534657d --- /dev/null +++ b/sw/CppunitTest_sw_xsltimport.mk @@ -0,0 +1,65 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*- +# +# This file is part of the Collabora Office project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,sw_xsltimport)) + +$(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_xsltimport)) + +$(eval $(call gb_CppunitTest_add_exception_objects,sw_xsltimport, \ + sw/qa/extras/xsltimport/xsltimport \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,sw_xsltimport, \ + comphelper \ + cppu \ + cppuhelper \ + i18nlangtag \ + sal \ + sfx \ + subsequenttest \ + sw \ + swqahelper \ + test \ + tl \ + unotest \ + utl \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_externals,sw_xsltimport,\ + boost_headers \ + libxml2 \ +)) + +$(eval $(call gb_CppunitTest_set_include,sw_xsltimport,\ + -I$(SRCDIR)/sw/inc \ + -I$(SRCDIR)/sw/source/core/inc \ + -I$(SRCDIR)/sw/source/uibase/inc \ + -I$(SRCDIR)/sw/qa/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_api,sw_xsltimport,\ + udkapi \ + offapi \ + oovbaapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,sw_xsltimport)) +$(eval $(call gb_CppunitTest_use_vcl,sw_xsltimport)) + +$(eval $(call gb_CppunitTest_use_rdb,sw_xsltimport,services)) + +$(eval $(call gb_CppunitTest_use_configuration,sw_xsltimport)) + +$(eval $(call gb_CppunitTest_use_packages,sw_xsltimport,\ + filter_xslt \ +)) + +# vim: set noet sw=4 ts=4: \ No newline at end of file diff --git a/sw/Module_sw.mk b/sw/Module_sw.mk index 55506375b6e3..0f7283cd8ee8 100644 --- a/sw/Module_sw.mk +++ b/sw/Module_sw.mk @@ -132,6 +132,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\ CppunitTest_sw_txtexport \ CppunitTest_sw_txtencexport \ CppunitTest_sw_txtimport \ + CppunitTest_sw_xsltimport \ CppunitTest_sw_uiwriter \ CppunitTest_sw_uiwriter2 \ CppunitTest_sw_uiwriter3 \ diff --git a/sw/qa/extras/xsltimport/data/testReplaceSpaces.xslt b/sw/qa/extras/xsltimport/data/testReplaceSpaces.xslt new file mode 100644 index 000000000000..96b51622900a --- /dev/null +++ b/sw/qa/extras/xsltimport/data/testReplaceSpaces.xslt @@ -0,0 +1 @@ + test \ No newline at end of file diff --git a/sw/qa/extras/xsltimport/xsltimport.cxx b/sw/qa/extras/xsltimport/xsltimport.cxx new file mode 100644 index 000000000000..6af29f0c4530 --- /dev/null +++ b/sw/qa/extras/xsltimport/xsltimport.cxx @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the Collabora Office project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +namespace +{ +class XSLTImportTest : public SwModelTestBase +{ +public: + XSLTImportTest() : + SwModelTestBase(u"/sw/qa/extras/xsltimport/data/"_ustr) + {} +}; + +CPPUNIT_TEST_FIXTURE(XSLTImportTest, testReplaceSpaces) +{ + createSwDoc("testReplaceSpaces.xslt"); + uno::Reference xPara(getParagraphOrTable(1), uno::UNO_QUERY_THROW); + OUString sText = xPara->getString(); + CPPUNIT_ASSERT(sText.startsWith(" ")); + CPPUNIT_ASSERT(sText.endsWith("test")); + CPPUNIT_ASSERT_EQUAL(static_cast(10004), sText.getLength()); +} + +} // end of anonymous namespace +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ \ No newline at end of file