summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorŁukasz Leszko <leszko.lucas@gmail.com>2022-03-17 17:13:24 +0100
committerMike Kaganski <mike.kaganski@collabora.com>2022-08-30 06:34:06 +0200
commit59ddcb0445da12f2b912f1a8a876117fec112c41 (patch)
treee6862534ab6c9d81edd7dc271311c82718bb766f /sc
parenta606244d9aa0054988caf1859efb7f26d38748cf (diff)
tdf#90299 Fix saving external links as relative
In current build some links to external xls files are not saved as relative even if "Save URLs relative to file system" option is checked. This patch aims to solve this issue. Change-Id: I6d0984bdcdeef57b227c8ab1353e002fa4355fc9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131711 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'sc')
-rw-r--r--sc/qa/unit/data/xls/tdf90299.xlsbin0 -> 5632 bytes
-rw-r--r--sc/qa/unit/subsequent_export_test.cxx77
-rw-r--r--sc/source/filter/excel/xehelper.cxx76
3 files changed, 129 insertions, 24 deletions
diff --git a/sc/qa/unit/data/xls/tdf90299.xls b/sc/qa/unit/data/xls/tdf90299.xls
new file mode 100644
index 000000000000..0028e11cfd51
--- /dev/null
+++ b/sc/qa/unit/data/xls/tdf90299.xls
Binary files differ
diff --git a/sc/qa/unit/subsequent_export_test.cxx b/sc/qa/unit/subsequent_export_test.cxx
index 15155636d2a1..b460319bd0a3 100644
--- a/sc/qa/unit/subsequent_export_test.cxx
+++ b/sc/qa/unit/subsequent_export_test.cxx
@@ -44,6 +44,10 @@
#include <editeng/fhgtitem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/colritem.hxx>
+#include <osl/file.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <unotools/tempfile.hxx>
#include <unotools/useroptions.hxx>
#include <tools/datetime.hxx>
@@ -182,6 +186,7 @@ public:
void testPreserveTextWhitespace2XLSX();
void testTdf113646();
void testDateStandardfilterXLSX();
+ void testTdf90299();
CPPUNIT_TEST_SUITE(ScExportTest);
CPPUNIT_TEST(test);
@@ -287,6 +292,7 @@ public:
CPPUNIT_TEST(testMoveCellAnchoredShapesODS);
CPPUNIT_TEST(testTdf113646);
CPPUNIT_TEST(testDateStandardfilterXLSX);
+ CPPUNIT_TEST(testTdf90299);
CPPUNIT_TEST_SUITE_END();
private:
@@ -4519,6 +4525,77 @@ void ScExportTest::testDateStandardfilterXLSX()
xDocSh->DoClose();
}
+void ScExportTest::testTdf90299()
+{
+ utl::TempFile aTmpDirectory1(nullptr, true);
+ utl::TempFile aTmpDirectory2(nullptr, true);
+ utl::TempFile aSavedFile(&aTmpDirectory1.GetURL());
+
+ struct
+ {
+ void checkFormula(ScDocShellRef xShell, OUString aExpectedFormula)
+ {
+ CPPUNIT_ASSERT(xShell.is());
+ xShell->ReloadAllLinks();
+
+ ScDocument& rDoc = xShell->GetDocument();
+
+ ScAddress aPos(0, 0, 0);
+ ScTokenArray* pCode = getTokens(rDoc, aPos);
+ CPPUNIT_ASSERT_MESSAGE("empty token array", pCode);
+
+ OUString aFormula = toString(rDoc, aPos, *pCode, rDoc.GetGrammar());
+
+ CPPUNIT_ASSERT_EQUAL(aExpectedFormula, aFormula);
+ }
+
+ } aCheckShell;
+
+ OUString aReferencedFileURL;
+ OUString aReferencingFileURL;
+ createFileURL(u"tdf90299.", u"xls", aReferencingFileURL);
+
+ auto eError = osl::File::copy(aReferencingFileURL, aTmpDirectory1.GetURL() + "/tdf90299.xls");
+ CPPUNIT_ASSERT_EQUAL(osl::File::E_None, eError);
+
+ aReferencingFileURL = aTmpDirectory1.GetURL() + "/tdf90299.xls";
+ aReferencedFileURL = aTmpDirectory1.GetURL() + "/dummy.xls";
+
+ ScDocShellRef xShell = load(aReferencingFileURL, FORMAT_XLS);
+ aCheckShell.checkFormula(xShell, "'" + aReferencedFileURL + "'#$Sheet1.A1");
+
+ aReferencingFileURL = aSavedFile.GetURL();
+
+ FileFormat afilterFormat = ScBootstrapFixture::getFileFormats()[FORMAT_XLS];
+ OUString aFilterName(afilterFormat.pFilterName, strlen(afilterFormat.pFilterName),
+ RTL_TEXTENCODING_UTF8);
+ OUString aFilterType(afilterFormat.pTypeName, strlen(afilterFormat.pTypeName),
+ RTL_TEXTENCODING_UTF8);
+
+ SfxMedium aStoreMedium(aReferencingFileURL, StreamMode::STD_WRITE);
+
+ auto pExportFilter = std::make_shared<SfxFilter>(
+ aFilterName, OUString(), afilterFormat.nFormatType, SotClipboardFormatId::NONE, aFilterType,
+ OUString(), OUString(), "private:factory/scalc*");
+ pExportFilter->SetVersion(SOFFICE_FILEFORMAT_CURRENT);
+
+ aStoreMedium.SetFilter(pExportFilter);
+
+ xShell->DoSaveAs(aStoreMedium);
+ xShell->DoClose();
+
+ eError = osl::File::copy(aReferencingFileURL, aTmpDirectory2.GetURL() + "/tdf90299.xls");
+ CPPUNIT_ASSERT_EQUAL(osl::File::E_None, eError);
+
+ aReferencingFileURL = aTmpDirectory2.GetURL() + "/tdf90299.xls";
+ aReferencedFileURL = aTmpDirectory2.GetURL() + "/dummy.xls";
+
+ xShell = load(aReferencingFileURL, FORMAT_XLS);
+ aCheckShell.checkFormula(xShell, "'" + aReferencedFileURL + "'#$Sheet1.A1");
+
+ xShell->DoClose();
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/source/filter/excel/xehelper.cxx b/sc/source/filter/excel/xehelper.cxx
index 2e5ebba684c4..2025e65a7bd2 100644
--- a/sc/source/filter/excel/xehelper.cxx
+++ b/sc/source/filter/excel/xehelper.cxx
@@ -23,6 +23,10 @@
#include <com/sun/star/i18n/XBreakIterator.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/uri/XUriReference.hpp>
+#include <com/sun/star/uri/XUriReferenceFactory.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <comphelper/processfactory.hxx>
#include <o3tl/string_view.hxx>
#include <sfx2/objsh.hxx>
#include <vcl/font.hxx>
@@ -40,6 +44,7 @@
#include <editeng/escapementitem.hxx>
#include <editeng/svxfont.hxx>
#include <editeng/editids.hrc>
+#include <osl/file.hxx>
#include <document.hxx>
#include <docpool.hxx>
@@ -887,34 +892,26 @@ namespace {
/** Encodes special parts of the path, i.e. directory separators and volume names.
@param pTableName Pointer to a table name to be encoded in this path, or 0. */
OUString lclEncodeDosPath(
- XclBiff eBiff, std::u16string_view path, std::u16string_view rBase, const OUString* pTableName)
+ XclBiff eBiff, std::u16string_view path, bool bIsRel, const OUString* pTableName)
{
OUStringBuffer aBuf;
if (!path.empty())
{
- std::u16string_view aOldPath = path;
aBuf.append(EXC_URLSTART_ENCODED);
- if ( aOldPath.length() > 2 && o3tl::starts_with(aOldPath, u"\\\\") )
+ if ( path.length() > 2 && o3tl::starts_with(path, u"\\\\") )
{
// UNC
aBuf.append(EXC_URL_DOSDRIVE).append('@');
- aOldPath = aOldPath.substr(2);
+ path = path.substr(2);
}
- else if ( aOldPath.length() > 2 && o3tl::starts_with(aOldPath.substr(1), u":\\") )
+ else if ( path.length() > 2 && o3tl::starts_with(path.substr(1), u":\\") )
{
- // drive letter
- sal_Unicode cThisDrive = rBase.empty() ? ' ' : rBase[0];
- sal_Unicode cDrive = aOldPath[0];
- if (cThisDrive == cDrive)
- // This document and the referenced document are under the same drive.
- aBuf.append(EXC_URL_DRIVEROOT);
- else
- aBuf.append(EXC_URL_DOSDRIVE).append(cDrive);
- aOldPath = aOldPath.substr(3);
+ aBuf.append(EXC_URL_DOSDRIVE).append(path[0]);
+ path = path.substr(3);
}
- else
+ else if ( !bIsRel )
{
// URL probably points to a document on a Unix-like file system
aBuf.append(EXC_URL_DRIVEROOT);
@@ -922,23 +919,23 @@ OUString lclEncodeDosPath(
// directories
auto nPos = std::u16string_view::npos;
- while((nPos = aOldPath.find('\\')) != std::u16string_view::npos)
+ while((nPos = path.find('\\')) != std::u16string_view::npos)
{
- if ( o3tl::starts_with(aOldPath, u"..") )
+ if ( o3tl::starts_with(path, u"..") )
// parent dir (NOTE: the MS-XLS spec doesn't mention this, and
// Excel seems confused by this token).
aBuf.append(EXC_URL_PARENTDIR);
else
- aBuf.append(aOldPath.substr(0,nPos)).append(EXC_URL_SUBDIR);
+ aBuf.append(path.substr(0,nPos)).append(EXC_URL_SUBDIR);
- aOldPath = aOldPath.substr(nPos + 1);
+ path = path.substr(nPos + 1);
}
// file name
if (pTableName) // enclose file name in brackets if table name follows
- aBuf.append('[').append(aOldPath).append(']');
+ aBuf.append('[').append(path).append(']');
else
- aBuf.append(aOldPath);
+ aBuf.append(path);
}
else // empty URL -> self reference
{
@@ -968,13 +965,44 @@ OUString lclEncodeDosPath(
return aBuf.makeStringAndClear();
}
+bool isUrlRelative(const OUString& aUrl)
+{
+ css::uno::Reference<css::uri::XUriReferenceFactory> xUriFactory(
+ css::uri::UriReferenceFactory::create(
+ comphelper::getProcessComponentContext()));
+ css::uno::Reference<css::uri::XUriReference> xUri(xUriFactory->parse(aUrl));
+
+ return !xUri->isAbsolute();
+}
+
} // namespace
OUString XclExpUrlHelper::EncodeUrl( const XclExpRoot& rRoot, std::u16string_view rAbsUrl, const OUString* pTableName )
{
- OUString aDosPath = INetURLObject(rAbsUrl).getFSysPath(FSysStyle::Dos);
- OUString aDosBase = INetURLObject(rRoot.GetBasePath()).getFSysPath(FSysStyle::Dos);
- return lclEncodeDosPath(rRoot.GetBiff(), aDosPath, aDosBase, pTableName);
+ OUString aDosPath;
+ bool bIsRel = false;
+
+ if (rRoot.IsRelUrl())
+ {
+ OUString aUrlPath = INetURLObject::GetRelURL(
+ rRoot.GetBasePath(), OUString(rAbsUrl),
+ INetURLObject::EncodeMechanism::All,
+ INetURLObject::DecodeMechanism::NONE,
+ RTL_TEXTENCODING_UTF8, FSysStyle::Detect
+ );
+
+ if (isUrlRelative(aUrlPath))
+ {
+ bIsRel = true;
+ osl::FileBase::getSystemPathFromFileURL(aUrlPath, aDosPath);
+ aDosPath = aDosPath.replaceAll(u"/", u"\\");
+ }
+ }
+
+ if (!bIsRel)
+ aDosPath = INetURLObject(rAbsUrl).getFSysPath(FSysStyle::Dos);
+
+ return lclEncodeDosPath(rRoot.GetBiff(), aDosPath, bIsRel, pTableName);
}
OUString XclExpUrlHelper::EncodeDde( std::u16string_view rApplic, std::u16string_view rTopic )