cui/source/options/optfltr.cxx | 10 cui/source/options/optfltr.hxx | 1 cui/uiconfig/ui/optfltrembedpage.ui | 63 + desktop/qa/desktop_app/test_desktop_app.cxx | 23 desktop/source/app/cmdlineargs.cxx | 10 include/svl/documentlockfile.hxx | 39 include/svl/lockfilecommon.hxx | 21 include/svl/msodocumentlockfile.hxx | 86 + include/svl/sharecontrolfile.hxx | 2 include/unotools/fltrcfg.hxx | 3 officecfg/registry/schema/org/openoffice/Office/Common.xcs | 8 sfx2/source/doc/docfile.cxx | 132 +- sfx2/source/doc/objstor.cxx | 14 svl/CppunitTest_svl_lockfiles.mk | 52 svl/Library_svl.mk | 3 svl/Module_svl.mk | 1 svl/qa/unit/lockfiles/test_lockfiles.cxx | 712 +++++++++++++ svl/source/misc/documentlockfile.cxx | 140 +- svl/source/misc/lockfilecommon.cxx | 37 svl/source/misc/msodocumentlockfile.cxx | 263 ++++ svl/source/misc/sharecontrolfile.cxx | 6 sw/source/core/layout/fly.cxx | 5 sw/source/ui/config/optcomp.cxx | 26 sw/source/uibase/docvw/FloatingTableButton.cxx | 9 sw/source/uibase/docvw/FrameControlsManager.cxx | 4 sw/source/uibase/inc/FloatingTableButton.hxx | 4 sw/source/uibase/inc/FrameControlsManager.hxx | 2 unotools/source/config/fltrcfg.cxx | 27 28 files changed, 1497 insertions(+), 206 deletions(-)
New commits: commit 82c7ecc4852a6ff39343a43f91c410bd72d2b702 Author: Tamás Zolnai <[email protected]> AuthorDate: Sun Apr 28 15:21:39 2019 +0200 Commit: Tamás Zolnai <[email protected]> CommitDate: Thu Jun 20 14:23:21 2019 +0200 WebDav: Don't unlock the file during saving of a document Otherwise it can happen that the file is locked by someone else during the saving method is running. I just extended the scope of the existing DisableUnlockWebDAV() calls a bit. In case of webdav it does not cause an issue to avoid unlocking the file before locking it again with an other SfxMedium. Change-Id: I6ac4e3326c63c9e184a7710ce8994cac1ed79449 Reviewed-on: https://gerrit.libreoffice.org/71484 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <[email protected]> (cherry picked from commit fdab153636ad7e3ce4b09836a63d2fa11b42e728) diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx index 61e94cfc1c94..59293e3e9cb1 100644 --- a/sfx2/source/doc/objstor.cxx +++ b/sfx2/source/doc/objstor.cxx @@ -1187,6 +1187,10 @@ bool SfxObjectShell::SaveTo_Impl && !rMedium.GetName().equalsIgnoreAsciiCase("private:stream") && ::utl::UCBContentHelper::EqualURLs( pMedium->GetName(), rMedium.GetName() ) ) { + // Do not unlock the file during saving. + // need to modify this for WebDAV if this method is called outside of + // the process of saving a file + pMedium->DisableUnlockWebDAV(); bStoreToSameLocation = true; if ( pMedium->DocNeedsFileDateCheck() ) @@ -1287,6 +1291,7 @@ bool SfxObjectShell::SaveTo_Impl } } } + pMedium->DisableUnlockWebDAV(false); } else { @@ -1706,10 +1711,6 @@ bool SfxObjectShell::SaveTo_Impl return bOk; } - -// This method contains a call to disable the UNLOCK of a WebDAV resource, that work while saving a file. -// If the method is called from another process (e.g. not when saving a file), -// that disabling needs tweaking bool SfxObjectShell::DisconnectStorage_Impl( SfxMedium& rSrcMedium, SfxMedium& rTargetMedium ) { // this method disconnects the storage from source medium, and attaches it to the backup created by the target medium @@ -1730,12 +1731,7 @@ bool SfxObjectShell::DisconnectStorage_Impl( SfxMedium& rSrcMedium, SfxMedium& r rTargetMedium.ResetError(); xOptStorage->writeAndAttachToStream( uno::Reference< io::XStream >() ); rSrcMedium.CanDisposeStorage_Impl( false ); - // need to modify this for WebDAV if this method is called outside - // the process of saving a file - rSrcMedium.DisableUnlockWebDAV(); rSrcMedium.Close(); - // see comment on the previous third row - rSrcMedium.DisableUnlockWebDAV( false ); // now try to create the backup rTargetMedium.GetBackup_Impl(); commit 32f7ecd68f8d64fa4651ba9efd82feaa4448a8d5 Author: Tamás Zolnai <[email protected]> AuthorDate: Wed Apr 17 12:33:13 2019 +0200 Commit: Tamás Zolnai <[email protected]> CommitDate: Thu Jun 20 14:23:21 2019 +0200 SharePoint connection: Better handling of encoded URLs Handle %7c with small letters. Make sure that the output parameter's content is not affected by decoding. Change-Id: Ie3faad2461815497c0edfb04a589fc57aeb7d66b Reviewed-on: https://gerrit.libreoffice.org/70873 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <[email protected]> (cherry picked from commit f6dc5636c1eda8aebeac3f7b85dd61499523d6a3) diff --git a/desktop/qa/desktop_app/test_desktop_app.cxx b/desktop/qa/desktop_app/test_desktop_app.cxx index 055c8cf5434e..1a027dfade78 100644 --- a/desktop/qa/desktop_app/test_desktop_app.cxx +++ b/desktop/qa/desktop_app/test_desktop_app.cxx @@ -113,7 +113,7 @@ void Test::testTdf100837() { { // 3. Test enocded URLs - TestSupplier supplier{ "foo", "ms-word:ofe%7Cu%7Cbar1", "ms-word:ofv%7Cu%7Cbar2", "ms-word:nft%7Cu%7Cbar3", "baz" }; + TestSupplier supplier{ "foo", "ms-word:ofe%7Cu%7cbar1", "ms-word:ofv%7cu%7Cbar2", "ms-word:nft%7Cu%7cbar3", "baz" }; desktop::CommandLineArgs args(supplier); auto vOpenList = args.GetOpenList(); auto vForceOpenList = args.GetForceOpenList(); diff --git a/desktop/source/app/cmdlineargs.cxx b/desktop/source/app/cmdlineargs.cxx old mode 100755 new mode 100644 index acb266eb335e..30d0c3f4cced --- a/desktop/source/app/cmdlineargs.cxx +++ b/desktop/source/app/cmdlineargs.cxx @@ -131,25 +131,25 @@ CommandLineEvent CheckOfficeURI(/* in,out */ OUString& arg, CommandLineEvent cur long nURIlen = -1; // URL might be encoded - rest1 = rest1.replaceAll("%7C", "|"); + OUString decoded_rest = rest1.replaceAll("%7C", "|").replaceAll("%7c", "|"); // 2. Discriminate by command name (incl. 1st command argument descriptor) // Extract URI: everything up to possible next argument - if (rest1.startsWith("ofv|u|", &rest2)) + if (decoded_rest.startsWith("ofv|u|", &rest2)) { // Open for view - override only in default mode if (curEvt == CommandLineEvent::Open) curEvt = CommandLineEvent::View; nURIlen = rest2.indexOf("|"); } - else if (rest1.startsWith("ofe|u|", &rest2)) + else if (decoded_rest.startsWith("ofe|u|", &rest2)) { // Open for editing - override only in default mode if (curEvt == CommandLineEvent::Open) curEvt = CommandLineEvent::ForceOpen; nURIlen = rest2.indexOf("|"); } - else if (rest1.startsWith("nft|u|", &rest2)) + else if (decoded_rest.startsWith("nft|u|", &rest2)) { // New from template - override only in default mode if (curEvt == CommandLineEvent::Open) commit f6c469e82cff213413584b3a4face70dcb3ede17 Author: Tamás Zolnai <[email protected]> AuthorDate: Tue Apr 16 10:45:12 2019 +0200 Commit: Tamás Zolnai <[email protected]> CommitDate: Thu Jun 20 14:23:21 2019 +0200 SharePoint connection: Handle encoded URL passed as command line argument Change-Id: I3352bf9ade88bd86f7ca3d53238364216547d52b Reviewed-on: https://gerrit.libreoffice.org/70830 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <[email protected]> (cherry picked from commit 2317ad572cc330c4c2de95065ef275f58a9c83a1) diff --git a/desktop/qa/desktop_app/test_desktop_app.cxx b/desktop/qa/desktop_app/test_desktop_app.cxx index ef588a580266..055c8cf5434e 100644 --- a/desktop/qa/desktop_app/test_desktop_app.cxx +++ b/desktop/qa/desktop_app/test_desktop_app.cxx @@ -110,6 +110,29 @@ void Test::testTdf100837() { CPPUNIT_ASSERT_EQUAL(OUString("bar"), vForceOpenList[0]); CPPUNIT_ASSERT_EQUAL(OUString("baz"), vForceOpenList[1]); } + + { + // 3. Test enocded URLs + TestSupplier supplier{ "foo", "ms-word:ofe%7Cu%7Cbar1", "ms-word:ofv%7Cu%7Cbar2", "ms-word:nft%7Cu%7Cbar3", "baz" }; + desktop::CommandLineArgs args(supplier); + auto vOpenList = args.GetOpenList(); + auto vForceOpenList = args.GetForceOpenList(); + auto vViewList = args.GetViewList(); + auto vForceNewList = args.GetForceNewList(); + // 2 documents go to Open list: foo; baz + CPPUNIT_ASSERT_EQUAL(decltype(vOpenList.size())(2), vOpenList.size()); + CPPUNIT_ASSERT_EQUAL(OUString("foo"), vOpenList[0]); + CPPUNIT_ASSERT_EQUAL(OUString("baz"), vOpenList[1]); + // 1 document goes to ForceOpen list: bar1 + CPPUNIT_ASSERT_EQUAL(decltype(vForceOpenList.size())(1), vForceOpenList.size()); + CPPUNIT_ASSERT_EQUAL(OUString("bar1"), vForceOpenList[0]); + // 1 document goes to View list: bar2 + CPPUNIT_ASSERT_EQUAL(decltype(vViewList.size())(1), vViewList.size()); + CPPUNIT_ASSERT_EQUAL(OUString("bar2"), vViewList[0]); + // 1 document goes to ForceNew list: bar3 + CPPUNIT_ASSERT_EQUAL(decltype(vForceNewList.size())(1), vForceNewList.size()); + CPPUNIT_ASSERT_EQUAL(OUString("bar3"), vForceNewList[0]); + } } CPPUNIT_TEST_SUITE_REGISTRATION(Test); diff --git a/desktop/source/app/cmdlineargs.cxx b/desktop/source/app/cmdlineargs.cxx old mode 100644 new mode 100755 index 52f96dd84d88..acb266eb335e --- a/desktop/source/app/cmdlineargs.cxx +++ b/desktop/source/app/cmdlineargs.cxx @@ -129,6 +129,10 @@ CommandLineEvent CheckOfficeURI(/* in,out */ OUString& arg, CommandLineEvent cur OUString rest2; long nURIlen = -1; + + // URL might be encoded + rest1 = rest1.replaceAll("%7C", "|"); + // 2. Discriminate by command name (incl. 1st command argument descriptor) // Extract URI: everything up to possible next argument if (rest1.startsWith("ofv|u|", &rest2)) commit 46e970b3bf8fe9ed1df94649a0e1cd23ba3ffce1 Author: Tamás Zolnai <[email protected]> AuthorDate: Sat Apr 6 13:25:27 2019 +0200 Commit: Tamás Zolnai <[email protected]> CommitDate: Thu Jun 20 14:23:21 2019 +0200 respect read-only config item: MSCompatibleFormsMenu Change-Id: I4eacbe8ad2025a54c13f4c0fa06e30e5ab59b721 Reviewed-on: https://gerrit.libreoffice.org/70344 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <[email protected]> (cherry picked from commit 1ac1fdbe5bb3139c81a331beb16c79e84d7c4f27) diff --git a/sw/source/ui/config/optcomp.cxx b/sw/source/ui/config/optcomp.cxx index 1a74d382a7ca..1876bb87fd19 100644 --- a/sw/source/ui/config/optcomp.cxx +++ b/sw/source/ui/config/optcomp.cxx @@ -37,6 +37,8 @@ #include <vector> #include <svtools/restartdialog.hxx> #include <comphelper/processfactory.hxx> +#include <officecfg/Office/Compatibility.hxx> +#include <vcl/svlbitm.hxx> using namespace ::com::sun::star::beans; using namespace ::com::sun::star::document; @@ -82,11 +84,31 @@ SwCompatibilityOptPage::SwCompatibilityOptPage(vcl::Window* pParent, const SfxIt m_pOptionsLB->SetStyle( m_pOptionsLB->GetStyle() | WB_HSCROLL | WB_HIDESELECTION ); m_pOptionsLB->SetHighlightRange(); - SvTreeListEntry* pEntry = m_pGlobalOptionsCLB->SvTreeListBox::InsertEntry( m_pGlobalOptionsLB->GetEntry( 0 ) ); + + // Set MSOCompatibleFormsMenu entry attributes + const bool bReadOnly = officecfg::Office::Compatibility::View::MSCompatibleFormsMenu::isReadOnly(); + const bool bChecked = m_aViewConfigItem.HasMSOCompatibleFormsMenu(); + + SvTreeListEntry* pEntry; + if(bReadOnly) + { + pEntry = m_pGlobalOptionsCLB->SvTreeListBox::InsertEntry( m_pGlobalOptionsLB->GetEntry( 0 ), nullptr, false, + TREELIST_APPEND, nullptr, SvLBoxButtonKind::DisabledCheckbox); + } + else + { + pEntry = m_pGlobalOptionsCLB->SvTreeListBox::InsertEntry( m_pGlobalOptionsLB->GetEntry( 0 ) ); + } + if ( pEntry ) { - m_pGlobalOptionsCLB->SetCheckButtonState( pEntry, SvButtonState::Unchecked ); + SvLBoxButton* pButton = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SvLBoxItemType::Button)); + if(bChecked) + pButton->SetStateChecked(); + else + pButton->SetStateUnchecked(); } + m_pGlobalOptionsLB->Clear(); m_pGlobalOptionsCLB->SetStyle( m_pGlobalOptionsCLB->GetStyle() | WB_HSCROLL | WB_HIDESELECTION ); commit 9ba0d45530d6316492a85bca08a51cee2d6a0041 Author: Tamás Zolnai <[email protected]> AuthorDate: Wed Apr 3 18:05:40 2019 +0200 Commit: Tamás Zolnai <[email protected]> CommitDate: Thu Jun 20 14:23:21 2019 +0200 svl.lockfiles.test: Create the temporary lock files in workdir Change-Id: I98b03754259c296ec8b4de2dddf6aee611bfe68a Reviewed-on: https://gerrit.libreoffice.org/70209 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <[email protected]> (cherry picked from commit 413461e3cf3a4b32a17419f67f879a8975c43987) diff --git a/svl/qa/unit/lockfiles/test_lockfiles.cxx b/svl/qa/unit/lockfiles/test_lockfiles.cxx index 5f23240f387c..b6c110ed6e48 100644 --- a/svl/qa/unit/lockfiles/test_lockfiles.cxx +++ b/svl/qa/unit/lockfiles/test_lockfiles.cxx @@ -29,6 +29,8 @@ namespace { class LockfileTest : public test::BootstrapFixture { + OUString generateTestURL(const OUString& sFileName) const; + public: void testLOLockFileURL(); void testLOLockFileContent(); @@ -92,11 +94,15 @@ OUString GetLockFileName(const svt::GenDocumentLockFile& rLockFile) return aDocURL.GetName(); } +OUString LockfileTest::generateTestURL(const OUString& sFileName) const +{ + return m_directories.getURLFromWorkdir("/CppunitTest/svl_lockfiles.test.user/") + sFileName; +} + void LockfileTest::testLOLockFileURL() { // Test the generated file name for LibreOffice lock files - OUString aTestODT - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testLOLockFileURL.odt"); + OUString aTestODT = generateTestURL("testLOLockFileURL.odt"); svt::DocumentLockFile aLockFile(aTestODT); CPPUNIT_ASSERT_EQUAL(OUString(".~lock.testLOLockFileURL.odt%23"), GetLockFileName(aLockFile)); @@ -105,8 +111,7 @@ void LockfileTest::testLOLockFileURL() void LockfileTest::testLOLockFileContent() { // Test the lockfile generated for the specified ODT document - OUString aTestODT - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testLOLockFileContent.odt"); + OUString aTestODT = generateTestURL("testLOLockFileContent.odt"); // Set user name SvtUserOptions aUserOpt; @@ -157,8 +162,7 @@ void LockfileTest::testLOLockFileContent() void LockfileTest::testLOLockFileRT() { // Test the lockfile generated for the specified ODT document - OUString aTestODT - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testLOLockFileRT.odt"); + OUString aTestODT = generateTestURL("testLOLockFileRT.odt"); // Set user name SvtUserOptions aUserOpt; @@ -188,8 +192,7 @@ void LockfileTest::testLOLockFileRT() void LockfileTest::testLOLockFileUnicodeUsername() { // Test the lockfile generated for the specified ODT document - OUString aTestODT = m_directories.getURLFromSrc( - "/svl/qa/unit/lockfiles/data/testLOLockFileUnicodeUsername.odt"); + OUString aTestODT = generateTestURL("testLOLockFileUnicodeUsername.odt"); // Set user name SvtUserOptions aUserOpt; @@ -215,8 +218,7 @@ void LockfileTest::testLOLockFileUnicodeUsername() void LockfileTest::testLOLockFileOverwrite() { - OUString aTestODT - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testLOLockFileOverwrite.odt"); + OUString aTestODT = generateTestURL("testLOLockFileOverwrite.odt"); // Set user name SvtUserOptions aUserOpt; @@ -257,62 +259,56 @@ void LockfileTest::testWordLockFileURL() // Word specific file format { - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testWordLockFileURL.docx"); + OUString aTestFile = generateTestURL("testWordLockFileURL.docx"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$stWordLockFileURL.docx"), GetLockFileName(aLockFile)); } // Eight character file name (cuts two characters) { - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.docx"); + OUString aTestFile = generateTestURL("12345678.docx"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$345678.docx"), GetLockFileName(aLockFile)); } // Seven character file name (cuts one character) { - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/1234567.docx"); + OUString aTestFile = generateTestURL("1234567.docx"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$234567.docx"), GetLockFileName(aLockFile)); } // Six character file name (cuts no character) { - OUString aTestFile = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/123456.docx"); + OUString aTestFile = generateTestURL("123456.docx"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$123456.docx"), GetLockFileName(aLockFile)); } // One character file name { - OUString aTestFile = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/1.docx"); + OUString aTestFile = generateTestURL("1.docx"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$1.docx"), GetLockFileName(aLockFile)); } // Test for ODT format { - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.odt"); + OUString aTestFile = generateTestURL("12345678.odt"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$345678.odt"), GetLockFileName(aLockFile)); } // Test for DOC format { - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.doc"); + OUString aTestFile = generateTestURL("12345678.doc"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$345678.doc"), GetLockFileName(aLockFile)); } // Test for RTF format { - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.rtf"); + OUString aTestFile = generateTestURL("12345678.rtf"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$345678.rtf"), GetLockFileName(aLockFile)); } @@ -322,31 +318,28 @@ void LockfileTest::testExcelLockFileURL() { // Test the generated file name for Excel lock files { - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testExcelLockFileURL.xlsx"); + OUString aTestFile = generateTestURL("testExcelLockFileURL.xlsx"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$testExcelLockFileURL.xlsx"), GetLockFileName(aLockFile)); } // Eight character file name { - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.xlsx"); + OUString aTestFile = generateTestURL("12345678.xlsx"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$12345678.xlsx"), GetLockFileName(aLockFile)); } // One character file name { - OUString aTestFile = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/1.xlsx"); + OUString aTestFile = generateTestURL("1.xlsx"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$1.xlsx"), GetLockFileName(aLockFile)); } // Test for ODS format { - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.ods"); + OUString aTestFile = generateTestURL("12345678.ods"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$12345678.ods"), GetLockFileName(aLockFile)); } @@ -356,8 +349,7 @@ void LockfileTest::testPowerPointLockFileURL() { // Test the generated file name for PowerPoint lock files { - OUString aTestFile = m_directories.getURLFromSrc( - "/svl/qa/unit/lockfiles/data/testPowerPointLockFileURL.pptx"); + OUString aTestFile = generateTestURL("testPowerPointLockFileURL.pptx"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$testPowerPointLockFileURL.pptx"), GetLockFileName(aLockFile)); @@ -365,31 +357,28 @@ void LockfileTest::testPowerPointLockFileURL() // Eight character file name { - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.pptx"); + OUString aTestFile = generateTestURL("12345678.pptx"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$12345678.pptx"), GetLockFileName(aLockFile)); } // One character file name { - OUString aTestFile = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/1.pptx"); + OUString aTestFile = generateTestURL("1.pptx"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$1.pptx"), GetLockFileName(aLockFile)); } // Test for PPT format { - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.ppt"); + OUString aTestFile = generateTestURL("12345678.ppt"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$12345678.ppt"), GetLockFileName(aLockFile)); } // Test for ODP format { - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.odp"); + OUString aTestFile = generateTestURL("/12345678.odp"); svt::MSODocumentLockFile aLockFile(aTestFile); CPPUNIT_ASSERT_EQUAL(OUString("~$12345678.odp"), GetLockFileName(aLockFile)); } @@ -398,8 +387,7 @@ void LockfileTest::testPowerPointLockFileURL() void LockfileTest::testWordLockFileContent() { // Test the lockfile generated for the specified DOCX document - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testWordLockFileContent.docx"); + OUString aTestFile = generateTestURL("testWordLockFileContent.docx"); // Set user name SvtUserOptions aUserOpt; @@ -453,8 +441,7 @@ void LockfileTest::testWordLockFileContent() void LockfileTest::testExcelLockFileContent() { // Test the lockfile generated for the specified XLSX document - OUString aTestFile - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testExcelLockFileContent.xlsx"); + OUString aTestFile = generateTestURL("testExcelLockFileContent.xlsx"); // Set user name SvtUserOptions aUserOpt; @@ -513,8 +500,7 @@ void LockfileTest::testExcelLockFileContent() void LockfileTest::testPowerPointLockFileContent() { // Test the lockfile generated for the specified PPTX document - OUString aTestFile = m_directories.getURLFromSrc( - "/svl/qa/unit/lockfiles/data/testPowerPointLockFileContent.pptx"); + OUString aTestFile = generateTestURL("testPowerPointLockFileContent.pptx"); // Set user name SvtUserOptions aUserOpt; @@ -574,8 +560,7 @@ void LockfileTest::testPowerPointLockFileContent() void LockfileTest::testWordLockFileRT() { - OUString aTestODT - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testWordLockFileRT.docx"); + OUString aTestODT = generateTestURL("testWordLockFileRT.docx"); // Set user name SvtUserOptions aUserOpt; @@ -596,8 +581,7 @@ void LockfileTest::testWordLockFileRT() void LockfileTest::testExcelLockFileRT() { - OUString aTestODT - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testExcelLockFileRT.xlsx"); + OUString aTestODT = generateTestURL("testExcelLockFileRT.xlsx"); // Set user name SvtUserOptions aUserOpt; @@ -618,8 +602,7 @@ void LockfileTest::testExcelLockFileRT() void LockfileTest::testPowerPointLockFileRT() { - OUString aTestODT - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testPowerPointLockFileRT.pptx"); + OUString aTestODT = generateTestURL("testPowerPointLockFileRT.pptx"); // Set user name SvtUserOptions aUserOpt; @@ -640,8 +623,7 @@ void LockfileTest::testPowerPointLockFileRT() void LockfileTest::testMSOLockFileLongUserName() { - OUString aTestODT = m_directories.getURLFromSrc( - "/svl/qa/unit/lockfiles/data/testMSOLockFileLongUserName.docx"); + OUString aTestODT = generateTestURL("testMSOLockFileLongUserName.docx"); // Set user name SvtUserOptions aUserOpt; @@ -667,8 +649,7 @@ void LockfileTest::testMSOLockFileLongUserName() void LockfileTest::testMSOLockFileUnicodeUsername() { // Test the lockfile generated for the specified ODT document - OUString aTestODT = m_directories.getURLFromSrc( - "/svl/qa/unit/lockfiles/data/testMSOLockFileUnicodeUsername.docx"); + OUString aTestODT = generateTestURL("testMSOLockFileUnicodeUsername.docx"); // Set user name SvtUserOptions aUserOpt; @@ -694,8 +675,7 @@ void LockfileTest::testMSOLockFileUnicodeUsername() void LockfileTest::testMSOLockFileOverwrite() { - OUString aTestODT - = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testMSOLockFileOverwrite.docx"); + OUString aTestODT = generateTestURL("testMSOLockFileOverwrite.docx"); // Set user name SvtUserOptions aUserOpt; @@ -725,7 +705,7 @@ void LockfileTest::testMSOLockFileOverwrite() } CPPUNIT_TEST_SUITE_REGISTRATION(LockfileTest); -} +} // namespace CPPUNIT_PLUGIN_IMPLEMENT(); commit c9dcc2172727cd75f512409c39eef460d44396dd Author: Tamás Zolnai <[email protected]> AuthorDate: Tue Mar 26 16:12:49 2019 +0100 Commit: Tamás Zolnai <[email protected]> CommitDate: Thu Jun 20 14:23:21 2019 +0200 MSO lockfiles: Deduplicate MSO lock file reading code The removed code was extracted to MSODocumentLockFile class so use that class here too. Use openStreamNoLock() for reading MSO lockfiles, because otherwise we can not read lock files written by MSO. Change-Id: Ib31cb9f3783d0b0ce784f900821047b9d32156f2 Reviewed-on: https://gerrit.libreoffice.org/69759 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <[email protected]> (cherry picked from commit ad47e9b1c0d3f1720665b2786090e8c0927b5b45) diff --git a/include/svl/documentlockfile.hxx b/include/svl/documentlockfile.hxx index 87334e4b73e7..79bb087c8362 100644 --- a/include/svl/documentlockfile.hxx +++ b/include/svl/documentlockfile.hxx @@ -50,7 +50,7 @@ public: protected: virtual void WriteEntryToStream( const LockFileEntry& aEntry, const css::uno::Reference< css::io::XOutputStream >& xStream ) = 0; - css::uno::Reference< css::io::XInputStream > OpenStream(); + virtual css::uno::Reference< css::io::XInputStream > OpenStream(); }; /// Class implementing reading and writing LO lockfiles. diff --git a/include/svl/msodocumentlockfile.hxx b/include/svl/msodocumentlockfile.hxx index 2c438f0178cb..5fa6fcbf10bf 100644 --- a/include/svl/msodocumentlockfile.hxx +++ b/include/svl/msodocumentlockfile.hxx @@ -64,6 +64,8 @@ protected: WriteEntryToStream(const LockFileEntry& aEntry, const css::uno::Reference<css::io::XOutputStream>& xStream) override; + virtual css::uno::Reference<css::io::XInputStream> OpenStream() override; + public: MSODocumentLockFile(const OUString& aOrigURL); virtual ~MSODocumentLockFile() override; diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx index dbdd98c294fb..a06ca65c65b9 100644 --- a/sfx2/source/doc/docfile.cxx +++ b/sfx2/source/doc/docfile.cxx @@ -893,84 +893,22 @@ void SfxMedium::SetEncryptionDataToStorage_Impl() namespace { -OUString tryMSOwnerFile(const INetURLObject& aLockfileURL) + +OUString tryMSOwnerFiles(const OUString& sDocURL) { + svt::MSODocumentLockFile aMSOLockFile(sDocURL); + LockFileEntry aData; try { - static osl::Mutex aMutex; - osl::MutexGuard aGuard(aMutex); - css::uno::Reference<css::ucb::XCommandEnvironment> xEnv; - ucbhelper::Content aSourceContent( - aLockfileURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), xEnv, - comphelper::getProcessComponentContext()); - - // Excel creates Owner Files with FILE_FLAG_DELETE_ON_CLOSE, so we need to open it with - // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE share mode - css::uno::Reference<css::io::XInputStream> xStream = aSourceContent.openStreamNoLock(); - if (!xStream) - return OUString(); - - const sal_Int32 nBufLen = 256; - css::uno::Sequence<sal_Int8> aBuf(nBufLen); - const sal_Int32 nRead = xStream->readBytes(aBuf, nBufLen); - xStream->closeInput(); - if (nRead >= 162) - { - // Reverse engineering of MS Office Owner Files format (MS Office 2016 tested). - // It starts with a single byte with name length, after which characters of username go - // in current Windows 8-bit codepage. - // For Word lockfiles, the name is followed by zero bytes up to position 54. - // For PowerPoint lockfiles, the name is followed by a single zero byte, and then 0x20 - // bytes up to position 55. - // For Excel lockfiles, the name is followed by 0x20 bytes up to position 55. - // At those positions in each type of lockfile, a name length 2-byte word goes, followed - // by UTF-16-LE-encoded copy of username. Spaces or some garbage follow up to the end of - // the lockfile (total 162 bytes for Word, 165 bytes for Excel/PowerPoint). - // Apparently MS Office does not allow username to be longer than 52 characters (trying - // to enter more in its options dialog results in error messages stating this limit). - const int nACPLen = aBuf[0]; - if (nACPLen > 0 && nACPLen <= 52) // skip wrong format - { - const sal_Int8* pBuf = aBuf.getConstArray() + 54; - int nUTF16Len = *pBuf; // try Word position - // If UTF-16 length is 0x20, then ACP length is also less than maximal, which means - // that in Word lockfile case, at least two preceeding bytes would be zero. Both - // Excel and PowerPoint lockfiles would have at least one of those bytes non-zero. - if (nUTF16Len == 0x20 && (*(pBuf - 1) != 0 || *(pBuf - 2) != 0)) - nUTF16Len = *++pBuf; // use Excel/PowerPoint position - - if (nUTF16Len > 0 && nUTF16Len <= 52) // skip wrong format - return OUString(reinterpret_cast<const sal_Unicode*>(pBuf + 2), nUTF16Len); - } - } + aData = aMSOLockFile.GetLockData(); } - catch (...) {} // we don't ever need to care about any exceptions here - - return OUString(); -} - -OUString tryMSOwnerFiles(const OUString& sDocURL) -{ - INetURLObject aURL(sDocURL); - if (aURL.HasError()) - return OUString(); - const OUString sFileName = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset); - if (sFileName.isEmpty()) - return OUString(); - const OUString sFileExt = aURL.GetFileExtension(); - const sal_Int32 nFileNameLen - = sFileName.getLength() - sFileExt.getLength() - (sFileExt.isEmpty() ? 0 : 1); - // Word, Excel, PowerPoint all prepend the filename with "~$". - aURL.SetName("~$" + sFileName, INetURLObject::EncodeMechanism::All); - OUString sUserData = tryMSOwnerFile(aURL); - // Additionally, Word strips first chars of the filename: 1 for length 7, 2 for length >=8. - if (sUserData.isEmpty() && nFileNameLen > 6) + catch( const uno::Exception& ) { - aURL.SetName("~$" + sFileName.copy((nFileNameLen == 7) ? 1 : 2), - INetURLObject::EncodeMechanism::All); - sUserData = tryMSOwnerFile(aURL); + return OUString(); } + OUString sUserData = aData[LockFileComponent::OOOUSERNAME]; + if (!sUserData.isEmpty()) sUserData += " (MS Office)"; // Mention the used office suite diff --git a/svl/source/misc/msodocumentlockfile.cxx b/svl/source/misc/msodocumentlockfile.cxx index e1afd70ef2e8..0309f86bc41e 100644 --- a/svl/source/misc/msodocumentlockfile.cxx +++ b/svl/source/misc/msodocumentlockfile.cxx @@ -11,10 +11,13 @@ #include <rtl/ustring.hxx> #include <sal/log.hxx> #include <algorithm> +#include <ucbhelper/content.hxx> +#include <comphelper/processfactory.hxx> #include <com/sun/star/io/IOException.hpp> #include <com/sun/star/io/XOutputStream.hpp> #include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> namespace svt { @@ -179,6 +182,17 @@ void MSODocumentLockFile::WriteEntryToStream( xOutput->writeBytes(aData); } +css::uno::Reference<css::io::XInputStream> MSODocumentLockFile::OpenStream() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + css::uno::Reference<css::ucb::XCommandEnvironment> xEnv; + ::ucbhelper::Content aSourceContent(GetURL(), xEnv, comphelper::getProcessComponentContext()); + + // the file can be opened readonly, no locking will be done + return aSourceContent.openStreamNoLock(); +} + LockFileEntry MSODocumentLockFile::GetLockData() { ::osl::MutexGuard aGuard(m_aMutex); commit dac99f6818e6e68198896e93835760b82df2703e Author: Tamás Zolnai <[email protected]> AuthorDate: Thu Jun 20 13:40:58 2019 +0200 Commit: Tamás Zolnai <[email protected]> CommitDate: Thu Jun 20 14:23:21 2019 +0200 Generate MSO lock files when the related MSO compat. option is set Added a new compatibility option to the Tools -> Load / Save -> Microsoft. When this option is set on the UI or or set in the configuration files LO generates lock files for MSO supported file formats, similar to the lock files MSO generates itself. Reviewed-on: https://gerrit.libreoffice.org/69678 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <[email protected]> (cherry picked from commit 41dc917b9b55b8c0c4307ffc58a1fb7257df2b69) Change-Id: I2f882723841162add01be9d3f7285a5162a60331 diff --git a/cui/source/options/optfltr.cxx b/cui/source/options/optfltr.cxx index 3d8b2fa04c52..ec3da63d7f5a 100644 --- a/cui/source/options/optfltr.cxx +++ b/cui/source/options/optfltr.cxx @@ -154,6 +154,7 @@ OfaMSFilterTabPage2::OfaMSFilterTabPage2( vcl::Window* pParent, const SfxItemSet get( aHighlightingRB, "highlighting"); get( aShadingRB, "shading" ); + get( aMSOLockFileCB, "mso_lockfile"); Size aControlSize(248, 55); aControlSize = LogicToPixel(aControlSize, MapMode(MapUnit::MapAppFont)); @@ -184,6 +185,7 @@ void OfaMSFilterTabPage2::dispose() m_pCheckLBContainer.clear(); aHighlightingRB.clear(); aShadingRB.clear(); + aMSOLockFileCB.clear(); SfxTabPage::dispose(); } @@ -253,6 +255,11 @@ bool OfaMSFilterTabPage2::FillItemSet( SfxItemSet* ) rOpt.SetCharBackground2Shading(); } + if( aMSOLockFileCB->IsValueChangedFromSaved() ) + { + rOpt.EnableMSOLockFileCreation(aMSOLockFileCB->IsChecked()); + } + return true; } @@ -319,6 +326,9 @@ void OfaMSFilterTabPage2::Reset( const SfxItemSet* ) aShadingRB->Check(); aHighlightingRB->SaveValue(); + + aMSOLockFileCB->Check(rOpt.IsMSOLockFileCreationIsEnabled()); + aMSOLockFileCB->SaveValue(); } void OfaMSFilterTabPage2::InsertEntry( const OUString& _rTxt, sal_IntPtr _nType ) diff --git a/cui/source/options/optfltr.hxx b/cui/source/options/optfltr.hxx index 9782fd773ee5..91f393d6b893 100644 --- a/cui/source/options/optfltr.hxx +++ b/cui/source/options/optfltr.hxx @@ -85,6 +85,7 @@ class OfaMSFilterTabPage2 : public SfxTabPage VclPtr<RadioButton> aHighlightingRB; VclPtr<RadioButton> aShadingRB; + VclPtr<CheckBox> aMSOLockFileCB; virtual ~OfaMSFilterTabPage2() override; virtual void dispose() override; diff --git a/cui/uiconfig/ui/optfltrembedpage.ui b/cui/uiconfig/ui/optfltrembedpage.ui index 0e65b6cdce69..df931247be30 100644 --- a/cui/uiconfig/ui/optfltrembedpage.ui +++ b/cui/uiconfig/ui/optfltrembedpage.ui @@ -1,4 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.20.4 --> <interface domain="cui"> <requires lib="gtk+" version="3.18"/> <requires lib="LibreOffice" version="1.0"/> @@ -48,8 +49,8 @@ <object class="GtkLabel" id="label2"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="xalign">0</property> <property name="label" translatable="yes" context="optfltrembedpage|label2">[L]: Load and convert the object</property> + <property name="xalign">0</property> </object> <packing> <property name="expand">False</property> @@ -61,8 +62,8 @@ <object class="GtkLabel" id="label3"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="xalign">0</property> <property name="label" translatable="yes" context="optfltrembedpage|label3">[S]: Convert and save the object</property> + <property name="xalign">0</property> </object> <packing> <property name="expand">False</property> @@ -88,8 +89,6 @@ <packing> <property name="left_attach">0</property> <property name="top_attach">0</property> - <property name="width">1</property> - <property name="height">1</property> </packing> </child> <child> @@ -184,8 +183,60 @@ <packing> <property name="left_attach">0</property> <property name="top_attach">1</property> - <property name="width">1</property> - <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="top_padding">6</property> + <property name="left_padding">12</property> + <child> + <object class="GtkButtonBox" id="buttonbox2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="layout_style">start</property> + <child> + <object class="GtkCheckButton" id="mso_lockfile"> + <property name="label" translatable="yes" context="optfltrembedpage|mso_lockfile">Create MSO lock file</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="optfltrembedpage|label5">Lock files</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> </packing> </child> </object> diff --git a/include/svl/lockfilecommon.hxx b/include/svl/lockfilecommon.hxx index e99ed64d7f36..97210d010279 100644 --- a/include/svl/lockfilecommon.hxx +++ b/include/svl/lockfilecommon.hxx @@ -68,7 +68,7 @@ public: static OUString GetCurrentLocalTime(); static LockFileEntry GenerateOwnEntry(); - INetURLObject ResolveLinks( const INetURLObject& aDocURL ) const; + static INetURLObject ResolveLinks( const INetURLObject& aDocURL ); }; } diff --git a/include/svl/msodocumentlockfile.hxx b/include/svl/msodocumentlockfile.hxx index 75f03ff16d4b..2c438f0178cb 100644 --- a/include/svl/msodocumentlockfile.hxx +++ b/include/svl/msodocumentlockfile.hxx @@ -55,9 +55,9 @@ class SVL_DLLPUBLIC MSODocumentLockFile : public GenDocumentLockFile private: OUString m_sOrigURL; - bool isWordFormat(const OUString& aOrigURL) const; - bool isExcelFormat(const OUString& aOrigURL) const; - bool isPowerPointFormat(const OUString& aOrigURL) const; + static bool isWordFormat(const OUString& aOrigURL); + static bool isExcelFormat(const OUString& aOrigURL); + static bool isPowerPointFormat(const OUString& aOrigURL); protected: virtual void @@ -74,6 +74,8 @@ public: virtual LockFileEntry GetLockData() override; virtual void RemoveFile() override; + + static bool IsMSOSupportedFileFormat(const OUString& aURL); }; } // namespace svt diff --git a/include/unotools/fltrcfg.hxx b/include/unotools/fltrcfg.hxx index ab0eb1364e81..bc5630cac444 100644 --- a/include/unotools/fltrcfg.hxx +++ b/include/unotools/fltrcfg.hxx @@ -91,6 +91,9 @@ public: void SetCharBackground2Highlighting(); void SetCharBackground2Shading(); + bool IsMSOLockFileCreationIsEnabled() const; + void EnableMSOLockFileCreation(bool bEnable); + static SvtFilterOptions& Get(); }; diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs b/officecfg/registry/schema/org/openoffice/Office/Common.xcs index ecc913106447..b790dab22ba9 100644 --- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs +++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs @@ -3820,6 +3820,14 @@ </info> <value>true</value> </prop> + <prop oor:name="CreateMSOLockFiles" oor:type="xs:boolean" oor:nillable="false"> + <info> + <desc>Specifies if LO should create MSO lock files next to the LO lock files + when openning a file. This makes MSO to be able to read the user name from + the lock file and show it for the user.</desc> + </info> + <value>false</value> + </prop> </group> <group oor:name="Export"> <info> diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx index 14723e934dc7..dbdd98c294fb 100644 --- a/sfx2/source/doc/docfile.cxx +++ b/sfx2/source/doc/docfile.cxx @@ -116,6 +116,7 @@ #include <sot/storage.hxx> #include <unotools/saveopt.hxx> #include <svl/documentlockfile.hxx> +#include <svl/msodocumentlockfile.hxx> #include <com/sun/star/document/DocumentRevisionListPersistence.hpp> #include <helper.hxx> @@ -130,7 +131,10 @@ #include <openflag.hxx> #include <officecfg/Office/Common.hxx> #include <comphelper/propertysequence.hxx> - +#include <vcl/weld.hxx> +#include <vcl/svapp.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/fltrcfg.hxx> #include <com/sun/star/io/WrongFormatException.hpp> #include <memory> @@ -255,6 +259,7 @@ public: bool m_bSalvageMode:1; bool m_bVersionsAlreadyLoaded:1; bool m_bLocked:1; + bool m_bMSOLockFileCreated : 1; bool m_bDisableUnlockWebDAV:1; bool m_bGotDateTime:1; bool m_bRemoveBackup:1; @@ -335,6 +340,7 @@ SfxMedium_Impl::SfxMedium_Impl() : m_bSalvageMode( false ), m_bVersionsAlreadyLoaded( false ), m_bLocked( false ), + m_bMSOLockFileCreated( false ), m_bDisableUnlockWebDAV( false ), m_bGotDateTime( false ), m_bRemoveBackup( false ), @@ -1400,6 +1406,15 @@ SfxMedium::LockFileResult SfxMedium::LockOrigFileOnDemand( bool bLoading, bool b try { ::svt::DocumentLockFile aLockFile( pImpl->m_aLogicName ); + + std::unique_ptr<svt::MSODocumentLockFile> pMSOLockFile; + const SvtFilterOptions& rOpt = SvtFilterOptions::Get(); + if (rOpt.IsMSOLockFileCreationIsEnabled() && svt::MSODocumentLockFile::IsMSOSupportedFileFormat(pImpl->m_aLogicName)) + { + pMSOLockFile.reset(new svt::MSODocumentLockFile(pImpl->m_aLogicName)); + pImpl->m_bMSOLockFileCreated = true; + } + bool bIoErr = false; if (!bHandleSysLocked) @@ -1407,6 +1422,8 @@ SfxMedium::LockFileResult SfxMedium::LockOrigFileOnDemand( bool bLoading, bool b try { bResult = aLockFile.CreateOwnLockFile(); + if(pMSOLockFile) + bResult &= pMSOLockFile->CreateOwnLockFile(); } catch (const uno::Exception&) { @@ -1431,6 +1448,9 @@ SfxMedium::LockFileResult SfxMedium::LockOrigFileOnDemand( bool bLoading, bool b bResult = true; // take the ownership over the lock file aLockFile.OverwriteOwnLockFile(); + + if(pMSOLockFile) + pMSOLockFile->OverwriteOwnLockFile(); } } @@ -1486,6 +1506,9 @@ SfxMedium::LockFileResult SfxMedium::LockOrigFileOnDemand( bool bLoading, bool b { // take the ownership over the lock file bResult = aLockFile.OverwriteOwnLockFile(); + + if(pMSOLockFile) + pMSOLockFile->OverwriteOwnLockFile(); } else if (bLoading && !bHandleSysLocked) eResult = LockFileResult::FailedLockFile; @@ -3032,6 +3055,31 @@ void SfxMedium::UnlockFile( bool bReleaseLockStream ) } catch( const uno::Exception& ) {} + + if(pImpl->m_bMSOLockFileCreated) + { + ::svt::MSODocumentLockFile aMSOLockFile( pImpl->m_aLogicName ); + + try + { + pImpl->m_bLocked = false; + // TODO/LATER: A warning could be shown in case the file is not the own one + aMSOLockFile.RemoveFile(); + } + catch( const io::WrongFormatException& ) + { + try + { + // erase the empty or corrupt file + aMSOLockFile.RemoveFileDirectly(); + } + catch( const uno::Exception& ) + {} + } + catch( const uno::Exception& ) + {} + pImpl->m_bMSOLockFileCreated = false; + } } #endif } diff --git a/svl/qa/unit/lockfiles/test_lockfiles.cxx b/svl/qa/unit/lockfiles/test_lockfiles.cxx index 8083c143f461..5f23240f387c 100644 --- a/svl/qa/unit/lockfiles/test_lockfiles.cxx +++ b/svl/qa/unit/lockfiles/test_lockfiles.cxx @@ -88,7 +88,7 @@ OUString readLockFile(const OUString& aSource) OUString GetLockFileName(const svt::GenDocumentLockFile& rLockFile) { - INetURLObject aDocURL = rLockFile.ResolveLinks(INetURLObject(rLockFile.GetURL())); + INetURLObject aDocURL = svt::LockFileCommon::ResolveLinks(INetURLObject(rLockFile.GetURL())); return aDocURL.GetName(); } diff --git a/svl/source/misc/lockfilecommon.cxx b/svl/source/misc/lockfilecommon.cxx index 30b53745c620..f0a1db6864e0 100644 --- a/svl/source/misc/lockfilecommon.cxx +++ b/svl/source/misc/lockfilecommon.cxx @@ -94,7 +94,7 @@ OUString LockFileCommon::GenerateURL( const OUString& aOrigURL, const OUString& } -INetURLObject LockFileCommon::ResolveLinks( const INetURLObject& aDocURL ) const +INetURLObject LockFileCommon::ResolveLinks( const INetURLObject& aDocURL ) { if ( aDocURL.HasError() ) throw lang::IllegalArgumentException(); diff --git a/svl/source/misc/msodocumentlockfile.cxx b/svl/source/misc/msodocumentlockfile.cxx index 938b36d5cd26..e1afd70ef2e8 100644 --- a/svl/source/misc/msodocumentlockfile.cxx +++ b/svl/source/misc/msodocumentlockfile.cxx @@ -18,9 +18,9 @@ namespace svt { -bool MSODocumentLockFile::isWordFormat(const OUString& aOrigURL) const +bool MSODocumentLockFile::isWordFormat(const OUString& aOrigURL) { - INetURLObject aDocURL = ResolveLinks(INetURLObject(aOrigURL)); + INetURLObject aDocURL = LockFileCommon::ResolveLinks(INetURLObject(aOrigURL)); return aDocURL.GetFileExtension().compareToIgnoreAsciiCase("DOC") == 0 || aDocURL.GetFileExtension().compareToIgnoreAsciiCase("DOCX") == 0 @@ -28,18 +28,18 @@ bool MSODocumentLockFile::isWordFormat(const OUString& aOrigURL) const || aDocURL.GetFileExtension().compareToIgnoreAsciiCase("ODT") == 0; } -bool MSODocumentLockFile::isExcelFormat(const OUString& aOrigURL) const +bool MSODocumentLockFile::isExcelFormat(const OUString& aOrigURL) { - INetURLObject aDocURL = ResolveLinks(INetURLObject(aOrigURL)); + INetURLObject aDocURL = LockFileCommon::ResolveLinks(INetURLObject(aOrigURL)); return //aDocURL.GetFileExtension().compareToIgnoreAsciiCase("XLS") || // MSO does not create lockfile for XLS aDocURL.GetFileExtension().compareToIgnoreAsciiCase("XLSX") == 0 || aDocURL.GetFileExtension().compareToIgnoreAsciiCase("ODS") == 0; } -bool MSODocumentLockFile::isPowerPointFormat(const OUString& aOrigURL) const +bool MSODocumentLockFile::isPowerPointFormat(const OUString& aOrigURL) { - INetURLObject aDocURL = ResolveLinks(INetURLObject(aOrigURL)); + INetURLObject aDocURL = LockFileCommon::ResolveLinks(INetURLObject(aOrigURL)); return aDocURL.GetFileExtension().compareToIgnoreAsciiCase("PPTX") == 0 || aDocURL.GetFileExtension().compareToIgnoreAsciiCase("PPT") == 0 @@ -56,7 +56,7 @@ MSODocumentLockFile::~MSODocumentLockFile() {} OUString MSODocumentLockFile::GenerateURL(const OUString& aOrigURL, const OUString& aPrefix) { - INetURLObject aDocURL = ResolveLinks(INetURLObject(aOrigURL)); + INetURLObject aDocURL = LockFileCommon::ResolveLinks(INetURLObject(aOrigURL)); OUString aURL = aDocURL.GetPartBeforeLastName(); aURL += aPrefix; @@ -239,6 +239,11 @@ void MSODocumentLockFile::RemoveFile() RemoveFileDirectly(); } +bool MSODocumentLockFile::IsMSOSupportedFileFormat(const OUString& aURL) +{ + return isWordFormat(aURL) || isExcelFormat(aURL) || isPowerPointFormat(aURL); +} + } // namespace svt /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/unotools/source/config/fltrcfg.cxx b/unotools/source/config/fltrcfg.cxx index 32a61fdae8a1..605239d62ced 100644 --- a/unotools/source/config/fltrcfg.cxx +++ b/unotools/source/config/fltrcfg.cxx @@ -25,6 +25,7 @@ #include <tools/debug.hxx> #include <tools/solar.h> #include <osl/diagnose.h> +#include <sal/log.hxx> #include <com/sun/star/uno/Sequence.hxx> @@ -54,10 +55,11 @@ enum class ConfigFlags { UseEnhancedFields = 0x0100000, WordWbctbl = 0x0200000, SmartArtShapeLoad = 0x0400000, - CharBackgroundToHighlighting = 0x8000000 + CharBackgroundToHighlighting = 0x8000000, + CreateMSOLockFiles = 0x2000000 }; namespace o3tl { - template<> struct typed_flags<ConfigFlags> : is_typed_flags<ConfigFlags, 0x87fff3f> {}; + template<> struct typed_flags<ConfigFlags> : is_typed_flags<ConfigFlags, 0xf7fff3f> {}; } class SvtAppFilterOptions_Impl : public utl::ConfigItem @@ -246,7 +248,8 @@ struct SvtFilterOptions_Impl ConfigFlags::ImpressSave | ConfigFlags::UseEnhancedFields | ConfigFlags::SmartArtShapeLoad | - ConfigFlags::CharBackgroundToHighlighting; + ConfigFlags::CharBackgroundToHighlighting| + ConfigFlags::CreateMSOLockFiles; Load(); } @@ -306,7 +309,7 @@ const Sequence<OUString>& GetPropertyNames() static Sequence<OUString> aNames; if(!aNames.getLength()) { - int nCount = 14; + int nCount = 15; aNames.realloc(nCount); static const char* aPropNames[] = { @@ -323,7 +326,8 @@ const Sequence<OUString>& GetPropertyNames() "Export/EnableWordPreview", // 10 "Import/ImportWWFieldsAsEnhancedFields", // 11 "Import/SmartArtToShapes", // 12 - "Export/CharBackgroundToHighlighting" // 13 + "Export/CharBackgroundToHighlighting", // 13 + "Import/CreateMSOLockFiles" // 14 }; OUString* pNames = aNames.getArray(); for(int i = 0; i < nCount; i++) @@ -365,6 +369,7 @@ static ConfigFlags lcl_GetFlag(sal_Int32 nProp) case 11: nFlag = ConfigFlags::UseEnhancedFields; break; case 12: nFlag = ConfigFlags::SmartArtShapeLoad; break; case 13: nFlag = ConfigFlags::CharBackgroundToHighlighting; break; + case 14: nFlag = ConfigFlags::CreateMSOLockFiles; break; default: OSL_FAIL("illegal value"); } @@ -632,7 +637,6 @@ bool SvtFilterOptions::IsEnableWordPreview() const return pImpl->IsFlag( ConfigFlags::EnableWordPreview ); } - bool SvtFilterOptions::IsCharBackground2Highlighting() const { return pImpl->IsFlag( ConfigFlags::CharBackgroundToHighlighting ); @@ -655,4 +659,15 @@ void SvtFilterOptions::SetCharBackground2Shading() SetModified(); } +bool SvtFilterOptions::IsMSOLockFileCreationIsEnabled() const +{ + return pImpl->IsFlag( ConfigFlags::CreateMSOLockFiles ); +} + +void SvtFilterOptions::EnableMSOLockFileCreation(bool bEnable) +{ + pImpl->SetFlag( ConfigFlags::CreateMSOLockFiles, bEnable ); + SetModified(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit f5946cd499f7d7de40b03f453f5b1c52e31a29fc Author: Tamás Zolnai <[email protected]> AuthorDate: Sat Mar 23 15:53:27 2019 +0100 Commit: Tamás Zolnai <[email protected]> CommitDate: Thu Jun 20 14:23:20 2019 +0200 Introduce new lockfile handler for MSO like lockfiles * Implement writing of MSO lockfiles * Grab the already implemented parsing code (tryMSOwnerFile method) and put it together into one class * Add tests about the generated URL for lockfiles and the lockfile content * MSO lockfiles are not written yet by LO, next step is to integrate this code into the locking mechanism. Reviewed-on: https://gerrit.libreoffice.org/69582 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <[email protected]> (cherry picked from commit 5db1e20b8b0942dac2d50f3cd34532bb61147020) Change-Id: I3b0ed1975cd57dfd006d4e1890b23c307890de5c Reviewed-on: https://gerrit.libreoffice.org/69842 Reviewed-by: Andras Timar <[email protected]> Tested-by: Andras Timar <[email protected]> diff --git a/include/svl/documentlockfile.hxx b/include/svl/documentlockfile.hxx index 25531dc3332e..87334e4b73e7 100644 --- a/include/svl/documentlockfile.hxx +++ b/include/svl/documentlockfile.hxx @@ -29,28 +29,41 @@ namespace com { namespace sun { namespace star { namespace io { class XOutputStr namespace svt { -class SVL_DLLPUBLIC DocumentLockFile : public LockFileCommon +/// Generalized class for LO and MSO lockfile handling. +class SVL_DLLPUBLIC GenDocumentLockFile : public LockFileCommon { - // the workaround for automated testing! - static bool m_bAllowInteraction; - - css::uno::Reference< css::io::XInputStream > OpenStream(); - - void WriteEntryToStream( const LockFileEntry& aEntry, const css::uno::Reference< css::io::XOutputStream >& xStream ); - public: - DocumentLockFile( const OUString& aOrigURL ); - ~DocumentLockFile(); + /// Specify the lockfile URL directly + GenDocumentLockFile( const OUString& aURL ); + /// Let the object generate and own URL based on the original file's URL and a prefix + GenDocumentLockFile( const OUString& aOrigURL, const OUString& aPrefix ); + virtual ~GenDocumentLockFile() override; bool CreateOwnLockFile(); - LockFileEntry GetLockData(); bool OverwriteOwnLockFile(); /// Delete the Lockfile, if current user is the owner - void RemoveFile(); + virtual void RemoveFile(); /// Only delete lockfile, disregarding ownership void RemoveFileDirectly(); - static bool IsInteractionAllowed() { return m_bAllowInteraction; } + virtual LockFileEntry GetLockData() = 0; + +protected: + virtual void WriteEntryToStream( const LockFileEntry& aEntry, const css::uno::Reference< css::io::XOutputStream >& xStream ) = 0; + css::uno::Reference< css::io::XInputStream > OpenStream(); +}; + +/// Class implementing reading and writing LO lockfiles. +class SVL_DLLPUBLIC DocumentLockFile : public GenDocumentLockFile +{ +protected: + virtual void WriteEntryToStream( const LockFileEntry& aEntry, const css::uno::Reference< css::io::XOutputStream >& xStream ) override; + +public: + DocumentLockFile( const OUString& aOrigURL ); + virtual ~DocumentLockFile() override; + + virtual LockFileEntry GetLockData() override; }; } diff --git a/include/svl/lockfilecommon.hxx b/include/svl/lockfilecommon.hxx index 4c5c6b5fe2e7..e99ed64d7f36 100644 --- a/include/svl/lockfilecommon.hxx +++ b/include/svl/lockfilecommon.hxx @@ -38,18 +38,27 @@ typedef o3tl::enumarray<LockFileComponent,OUString> LockFileEntry; namespace svt { -// This is a general implementation that is used in document lock file implementation and in sharing control file implementation +/// This is a general implementation that is used in document lock file implementation and in sharing control file implementation class SVL_DLLPUBLIC LockFileCommon { -protected: - ::osl::Mutex m_aMutex; +private: OUString m_aURL; - INetURLObject ResolveLinks( const INetURLObject& aDocURL ) const; +protected: + ::osl::Mutex m_aMutex; public: + /// Specify the lockfile URL directly + LockFileCommon( const OUString& aURL ); + /// Let the object generate and own URL based on the original file's URL and a prefix LockFileCommon( const OUString& aOrigURL, const OUString& aPrefix ); - ~LockFileCommon(); + virtual ~LockFileCommon(); + + const OUString& GetURL() const; + void SetURL(const OUString& aURL); + + /// This method generates the URL of the lock file based on the document URL and the specified prefix. + virtual OUString GenerateURL( const OUString& aOrigURL, const OUString& aPrefix ); static void ParseList( const css::uno::Sequence< sal_Int8 >& aBuffer, std::vector< LockFileEntry > &rOutput ); static LockFileEntry ParseEntry( const css::uno::Sequence< sal_Int8 >& aBuffer, sal_Int32& o_nCurPos ); @@ -58,6 +67,8 @@ public: static OUString GetOOOUserName(); static OUString GetCurrentLocalTime(); static LockFileEntry GenerateOwnEntry(); + + INetURLObject ResolveLinks( const INetURLObject& aDocURL ) const; }; } diff --git a/include/svl/msodocumentlockfile.hxx b/include/svl/msodocumentlockfile.hxx new file mode 100644 index 000000000000..75f03ff16d4b --- /dev/null +++ b/include/svl/msodocumentlockfile.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice 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/. + */ + +#ifndef INCLUDED_SVL_MSODOCUMENTLOCKFILE_HXX +#define INCLUDED_SVL_MSODOCUMENTLOCKFILE_HXX + +#include <svl/svldllapi.h> +#include <svl/lockfilecommon.hxx> +#include <svl/documentlockfile.hxx> + +#include <com/sun/star/lang/XComponent.hpp> + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace io +{ +class XInputStream; +} +} // namespace star +} // namespace sun +} // namespace com +namespace com +{ +namespace sun +{ +namespace star +{ +namespace io +{ +class XOutputStream; +} +} // namespace star +} // namespace sun +} // namespace com + +#define MSO_WORD_LOCKFILE_SIZE 162 +#define MSO_EXCEL_AND_POWERPOINT_LOCKFILE_SIZE 165 +#define MSO_USERNAME_MAX_LENGTH 52 + +namespace svt +{ +/// Class implementing reading and writing MSO lockfiles. +class SVL_DLLPUBLIC MSODocumentLockFile : public GenDocumentLockFile +{ +private: + OUString m_sOrigURL; + + bool isWordFormat(const OUString& aOrigURL) const; + bool isExcelFormat(const OUString& aOrigURL) const; + bool isPowerPointFormat(const OUString& aOrigURL) const; + +protected: + virtual void + WriteEntryToStream(const LockFileEntry& aEntry, + const css::uno::Reference<css::io::XOutputStream>& xStream) override; + +public: + MSODocumentLockFile(const OUString& aOrigURL); + virtual ~MSODocumentLockFile() override; + + /// Need to generate different lock file name for MSO. + virtual OUString GenerateURL(const OUString& aOrigURL, const OUString& aPrefix) override; + + virtual LockFileEntry GetLockData() override; + + virtual void RemoveFile() override; +}; +} // namespace svt + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/include/svl/sharecontrolfile.hxx b/include/svl/sharecontrolfile.hxx index 8dfa91669ddc..dd52d48da8f7 100644 --- a/include/svl/sharecontrolfile.hxx +++ b/include/svl/sharecontrolfile.hxx @@ -53,7 +53,7 @@ public: // The constructor will throw exception in case the stream can not be opened ShareControlFile( const OUString& aOrigURL ); - ~ShareControlFile(); + virtual ~ShareControlFile() override; std::vector< LockFileEntry > GetUsersData(); void SetUsersDataAndStore( const std::vector< LockFileEntry >& aUserNames ); diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx index 08848fd6808d..14723e934dc7 100644 --- a/sfx2/source/doc/docfile.cxx +++ b/sfx2/source/doc/docfile.cxx @@ -993,7 +993,7 @@ SfxMedium::ShowLockResult SfxMedium::ShowLockedDocumentDialog(const OUString& aD // show the interaction regarding the document opening uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler(); - if ( ::svt::DocumentLockFile::IsInteractionAllowed() && xHandler.is() && ( bIsLoading || !bHandleSysLocked || bOwnLock ) ) + if ( xHandler.is() && ( bIsLoading || !bHandleSysLocked || bOwnLock ) ) { OUString aDocumentURL = GetURLObject().GetLastName(INetURLObject::DecodeMechanism::WithCharset); diff --git a/svl/CppunitTest_svl_lockfiles.mk b/svl/CppunitTest_svl_lockfiles.mk new file mode 100644 index 000000000000..c93e78b45b8d --- /dev/null +++ b/svl/CppunitTest_svl_lockfiles.mk @@ -0,0 +1,52 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*- +# +# This file is part of the LibreOffice 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,svl_lockfiles)) + +$(eval $(call gb_CppunitTest_use_sdk_api,svl_lockfiles)) + +$(eval $(call gb_CppunitTest_use_api,svl_lockfiles,\ + udkapi \ + offapi \ + oovbaapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,svl_lockfiles)) + +$(eval $(call gb_CppunitTest_use_vcl,svl_lockfiles)) + + +$(eval $(call gb_CppunitTest_add_exception_objects,svl_lockfiles, \ + svl/qa/unit/lockfiles/test_lockfiles \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,svl_lockfiles, \ + comphelper \ + cppu \ + cppuhelper \ + tl \ + sal \ + svl \ + svt \ + sw \ + test \ + unotest \ + utl \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_rdb,svl_lockfiles,services)) + +$(eval $(call gb_CppunitTest_use_custom_headers,svl_lockfiles,\ + officecfg/registry \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,svl_lockfiles)) + +# vim: set noet sw=4 ts=4: diff --git a/svl/Library_svl.mk b/svl/Library_svl.mk index 2103a1483a45..4dad7be2a929 100644 --- a/svl/Library_svl.mk +++ b/svl/Library_svl.mk @@ -163,7 +163,8 @@ $(eval $(call gb_Library_add_exception_objects,svl,\ svl/source/misc/PasswordHelper \ svl/source/misc/adrparse \ $(if $(filter DESKTOP,$(BUILD_TYPE)),\ - svl/source/misc/documentlockfile) \ + svl/source/misc/documentlockfile \ + svl/source/misc/msodocumentlockfile) \ svl/source/misc/filenotation \ svl/source/misc/fstathelper \ svl/source/misc/getstringresource \ diff --git a/svl/Module_svl.mk b/svl/Module_svl.mk index d14e184b65a9..2569edb05b64 100644 --- a/svl/Module_svl.mk +++ b/svl/Module_svl.mk @@ -34,6 +34,7 @@ $(eval $(call gb_Module_add_check_targets,svl,\ CppunitTest_svl_itempool \ CppunitTest_svl_items \ CppunitTest_svl_lngmisc \ + CppunitTest_svl_lockfiles \ CppunitTest_svl_notify \ CppunitTest_svl_qa_cppunit \ CppunitTest_svl_urihelper \ diff --git a/svl/qa/unit/lockfiles/test_lockfiles.cxx b/svl/qa/unit/lockfiles/test_lockfiles.cxx new file mode 100644 index 000000000000..8083c143f461 --- /dev/null +++ b/svl/qa/unit/lockfiles/test_lockfiles.cxx @@ -0,0 +1,732 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice 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 <sal/config.h> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> +#include <test/bootstrapfixture.hxx> + +#include <unotest/directories.hxx> +#include <svl/lockfilecommon.hxx> +#include <svl/documentlockfile.hxx> +#include <svl/msodocumentlockfile.hxx> +#include <unotools/useroptions.hxx> +#include <comphelper/sequence.hxx> +#include <tools/stream.hxx> +#include <rtl/strbuf.hxx> +#include <osl/security.hxx> +#include <osl/socket.hxx> +#include <unotools/bootstrap.hxx> + +namespace +{ +class LockfileTest : public test::BootstrapFixture +{ +public: + void testLOLockFileURL(); + void testLOLockFileContent(); + void testLOLockFileRT(); + void testLOLockFileUnicodeUsername(); + void testLOLockFileOverwrite(); + void testWordLockFileURL(); + void testExcelLockFileURL(); + void testPowerPointLockFileURL(); + void testWordLockFileContent(); + void testExcelLockFileContent(); + void testPowerPointLockFileContent(); + void testWordLockFileRT(); + void testExcelLockFileRT(); + void testPowerPointLockFileRT(); + void testMSOLockFileLongUserName(); + void testMSOLockFileUnicodeUsername(); + void testMSOLockFileOverwrite(); + +private: + CPPUNIT_TEST_SUITE(LockfileTest); + CPPUNIT_TEST(testLOLockFileURL); + CPPUNIT_TEST(testLOLockFileContent); + CPPUNIT_TEST(testLOLockFileRT); + CPPUNIT_TEST(testLOLockFileUnicodeUsername); + CPPUNIT_TEST(testLOLockFileOverwrite); + CPPUNIT_TEST(testWordLockFileURL); + CPPUNIT_TEST(testExcelLockFileURL); + CPPUNIT_TEST(testPowerPointLockFileURL); + CPPUNIT_TEST(testWordLockFileContent); + CPPUNIT_TEST(testExcelLockFileContent); + CPPUNIT_TEST(testPowerPointLockFileContent); + CPPUNIT_TEST(testWordLockFileRT); + CPPUNIT_TEST(testExcelLockFileRT); + CPPUNIT_TEST(testPowerPointLockFileRT); + CPPUNIT_TEST(testMSOLockFileLongUserName); + CPPUNIT_TEST(testMSOLockFileUnicodeUsername); + CPPUNIT_TEST(testMSOLockFileOverwrite); + CPPUNIT_TEST_SUITE_END(); +}; + +OUString readLockFile(const OUString& aSource) +{ + SvFileStream aFileStream(aSource, StreamMode::READ); + std::size_t nSize = aFileStream.remainingSize(); + std::unique_ptr<sal_Int8[]> pBuffer(new sal_Int8[nSize]); + aFileStream.ReadBytes(pBuffer.get(), nSize); + + css::uno::Sequence<sal_Int8> aData(pBuffer.get(), nSize); + OStringBuffer aResult; + for (sal_Int8 nByte : aData) + { + aResult.append(static_cast<sal_Char>(nByte)); + } + return OStringToOUString(aResult.makeStringAndClear(), RTL_TEXTENCODING_UTF8); +} + +OUString GetLockFileName(const svt::GenDocumentLockFile& rLockFile) +{ + INetURLObject aDocURL = rLockFile.ResolveLinks(INetURLObject(rLockFile.GetURL())); + return aDocURL.GetName(); +} + +void LockfileTest::testLOLockFileURL() +{ + // Test the generated file name for LibreOffice lock files + OUString aTestODT + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testLOLockFileURL.odt"); + + svt::DocumentLockFile aLockFile(aTestODT); + CPPUNIT_ASSERT_EQUAL(OUString(".~lock.testLOLockFileURL.odt%23"), GetLockFileName(aLockFile)); +} + +void LockfileTest::testLOLockFileContent() +{ + // Test the lockfile generated for the specified ODT document + OUString aTestODT + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testLOLockFileContent.odt"); + + // Set user name + SvtUserOptions aUserOpt; + aUserOpt.SetToken(UserOptToken::FirstName, "LockFile"); + aUserOpt.SetToken(UserOptToken::LastName, "Test"); + + // Write the lock file and check the content + svt::DocumentLockFile aLockFile(aTestODT); + aLockFile.CreateOwnLockFile(); + OUString sLockFileContent(readLockFile(aLockFile.GetURL())); + aLockFile.RemoveFileDirectly(); + + // User name + sal_Int32 nFirstChar = 0; + sal_Int32 nNextComma = sLockFileContent.indexOf(',', nFirstChar); + OUString sUserName; + sUserName += aUserOpt.GetFirstName() + " "; + sUserName += aUserOpt.GetLastName(); + CPPUNIT_ASSERT_EQUAL(sUserName, sLockFileContent.copy(nFirstChar, nNextComma - nFirstChar)); + + // System user name + nFirstChar = nNextComma + 1; + nNextComma = sLockFileContent.indexOf(',', nFirstChar); + ::osl::Security aSecurity; + OUString sSysUserName; + aSecurity.getUserName(sSysUserName); + CPPUNIT_ASSERT_EQUAL(sSysUserName, sLockFileContent.copy(nFirstChar, nNextComma - nFirstChar)); + + // Local host + nFirstChar = nNextComma + 1; + nNextComma = sLockFileContent.indexOf(',', nFirstChar); + CPPUNIT_ASSERT_EQUAL(::osl::SocketAddr::getLocalHostname(), + sLockFileContent.copy(nFirstChar, nNextComma - nFirstChar)); + + // Skip date and time because it changes after the lock file was created + nFirstChar = nNextComma + 1; + nNextComma = sLockFileContent.indexOf(',', nFirstChar); + + // user url + nFirstChar = nNextComma + 1; + OUString aUserInstDir; + ::utl::Bootstrap::locateUserInstallation(aUserInstDir); + CPPUNIT_ASSERT_EQUAL( + aUserInstDir, + sLockFileContent.copy(nFirstChar, sLockFileContent.getLength() - nFirstChar - 1)); +} + +void LockfileTest::testLOLockFileRT() +{ + // Test the lockfile generated for the specified ODT document + OUString aTestODT + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testLOLockFileRT.odt"); + + // Set user name + SvtUserOptions aUserOpt; + aUserOpt.SetToken(UserOptToken::FirstName, "LockFile"); + aUserOpt.SetToken(UserOptToken::LastName, "Test"); + + // Write the lock file and read it back + svt::DocumentLockFile aLockFile(aTestODT); + LockFileEntry aOrigEntry = svt::LockFileCommon::GenerateOwnEntry(); + aLockFile.CreateOwnLockFile(); + LockFileEntry aRTEntry = aLockFile.GetLockData(); + + // Check whether the lock file attributes are the same + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::OOOUSERNAME], + aRTEntry[LockFileComponent::OOOUSERNAME]); + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::SYSUSERNAME], + aRTEntry[LockFileComponent::SYSUSERNAME]); + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::LOCALHOST], + aRTEntry[LockFileComponent::LOCALHOST]); + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::USERURL], + aRTEntry[LockFileComponent::USERURL]); + // LockFileComponent::EDITTIME can change + + aLockFile.RemoveFileDirectly(); +} + +void LockfileTest::testLOLockFileUnicodeUsername() +{ + // Test the lockfile generated for the specified ODT document + OUString aTestODT = m_directories.getURLFromSrc( + "/svl/qa/unit/lockfiles/data/testLOLockFileUnicodeUsername.odt"); + + // Set user name + SvtUserOptions aUserOpt; + sal_Unicode vFirstName[] = { 2351, 2676, 3117, 5279 }; + aUserOpt.SetToken(UserOptToken::FirstName, OUString(vFirstName, 4)); + sal_Unicode vLastName[] = { 671, 1245, 1422, 1822 }; + aUserOpt.SetToken(UserOptToken::LastName, OUString(vLastName, 4)); + + // Write the lock file and read it back + svt::DocumentLockFile aLockFile(aTestODT); + LockFileEntry aOrigEntry = svt::LockFileCommon::GenerateOwnEntry(); + aLockFile.CreateOwnLockFile(); + LockFileEntry aRTEntry = aLockFile.GetLockData(); + + // Check whether the lock file attributes are the same + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::OOOUSERNAME], + aRTEntry[LockFileComponent::OOOUSERNAME]); + CPPUNIT_ASSERT_EQUAL(OUString(aUserOpt.GetFirstName() + " " + aUserOpt.GetLastName()), + aOrigEntry[LockFileComponent::OOOUSERNAME]); + + aLockFile.RemoveFileDirectly(); +} + +void LockfileTest::testLOLockFileOverwrite() +{ + OUString aTestODT + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testLOLockFileOverwrite.odt"); + + // Set user name + SvtUserOptions aUserOpt; + aUserOpt.SetToken(UserOptToken::FirstName, "LockFile"); + aUserOpt.SetToken(UserOptToken::LastName, "Test"); + + // Write the lock file and read it back + svt::DocumentLockFile aLockFile(aTestODT); + aLockFile.CreateOwnLockFile(); + + // Change user name + aUserOpt.SetToken(UserOptToken::FirstName, "LockFile2"); + aUserOpt.SetToken(UserOptToken::LastName, "Test"); + + // Overwrite lockfile + svt::DocumentLockFile aLockFile2(aTestODT); + LockFileEntry aOrigEntry = svt::LockFileCommon::GenerateOwnEntry(); + aLockFile2.OverwriteOwnLockFile(); + + LockFileEntry aRTEntry = aLockFile.GetLockData(); + + // Check whether the lock file attributes are the same + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::OOOUSERNAME], + aRTEntry[LockFileComponent::OOOUSERNAME]); + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::SYSUSERNAME], + aRTEntry[LockFileComponent::SYSUSERNAME]); + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::LOCALHOST], + aRTEntry[LockFileComponent::LOCALHOST]); + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::USERURL], + aRTEntry[LockFileComponent::USERURL]); + + aLockFile2.RemoveFileDirectly(); +} + +void LockfileTest::testWordLockFileURL() +{ + // Test the generated file name for Word lock files + + // Word specific file format + { + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testWordLockFileURL.docx"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$stWordLockFileURL.docx"), GetLockFileName(aLockFile)); + } + + // Eight character file name (cuts two characters) + { + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.docx"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$345678.docx"), GetLockFileName(aLockFile)); + } + + // Seven character file name (cuts one character) + { + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/1234567.docx"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$234567.docx"), GetLockFileName(aLockFile)); + } + + // Six character file name (cuts no character) + { + OUString aTestFile = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/123456.docx"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$123456.docx"), GetLockFileName(aLockFile)); + } + + // One character file name + { + OUString aTestFile = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/1.docx"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$1.docx"), GetLockFileName(aLockFile)); + } + + // Test for ODT format + { + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.odt"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$345678.odt"), GetLockFileName(aLockFile)); + } + + // Test for DOC format + { + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.doc"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$345678.doc"), GetLockFileName(aLockFile)); + } + + // Test for RTF format + { + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.rtf"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$345678.rtf"), GetLockFileName(aLockFile)); + } +} + +void LockfileTest::testExcelLockFileURL() +{ + // Test the generated file name for Excel lock files + { + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testExcelLockFileURL.xlsx"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$testExcelLockFileURL.xlsx"), GetLockFileName(aLockFile)); + } + + // Eight character file name + { + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.xlsx"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$12345678.xlsx"), GetLockFileName(aLockFile)); + } + + // One character file name + { + OUString aTestFile = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/1.xlsx"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$1.xlsx"), GetLockFileName(aLockFile)); + } + + // Test for ODS format + { + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.ods"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$12345678.ods"), GetLockFileName(aLockFile)); + } +} + +void LockfileTest::testPowerPointLockFileURL() +{ + // Test the generated file name for PowerPoint lock files + { + OUString aTestFile = m_directories.getURLFromSrc( + "/svl/qa/unit/lockfiles/data/testPowerPointLockFileURL.pptx"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$testPowerPointLockFileURL.pptx"), + GetLockFileName(aLockFile)); + } + + // Eight character file name + { + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.pptx"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$12345678.pptx"), GetLockFileName(aLockFile)); + } + + // One character file name + { + OUString aTestFile = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/1.pptx"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$1.pptx"), GetLockFileName(aLockFile)); + } + + // Test for PPT format + { + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.ppt"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$12345678.ppt"), GetLockFileName(aLockFile)); + } + + // Test for ODP format + { + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/12345678.odp"); + svt::MSODocumentLockFile aLockFile(aTestFile); + CPPUNIT_ASSERT_EQUAL(OUString("~$12345678.odp"), GetLockFileName(aLockFile)); + } +} + +void LockfileTest::testWordLockFileContent() +{ + // Test the lockfile generated for the specified DOCX document + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testWordLockFileContent.docx"); + + // Set user name + SvtUserOptions aUserOpt; + aUserOpt.SetToken(UserOptToken::FirstName, "LockFile"); + aUserOpt.SetToken(UserOptToken::LastName, "Test"); + + // Write the lock file and check the content + svt::MSODocumentLockFile aLockFile(aTestFile); + aLockFile.CreateOwnLockFile(); + OUString sLockFileContent(readLockFile(aLockFile.GetURL())); + aLockFile.RemoveFileDirectly(); + + // First character is the size of the user name + OUString sUserName; + sUserName += aUserOpt.GetFirstName() + " "; + sUserName += aUserOpt.GetLastName(); + int nIndex = 0; + CPPUNIT_ASSERT_EQUAL(sUserName.getLength(), static_cast<sal_Int32>(sLockFileContent[nIndex])); + + // Then we have the user name + CPPUNIT_ASSERT_EQUAL(sUserName, sLockFileContent.copy(1, sUserName.getLength())); + + // We have some filling 0 bytes after the user name + for (nIndex = sUserName.getLength() + 1; nIndex < MSO_USERNAME_MAX_LENGTH + 2; ++nIndex) + { + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), static_cast<sal_Int32>(sLockFileContent[nIndex])); + } + + // Then we have the user name's length again + CPPUNIT_ASSERT_EQUAL(sUserName.getLength(), static_cast<sal_Int32>(sLockFileContent[nIndex])); + + // Then we have the user name again with 16 bit coding + for (int i = 0; i < sUserName.getLength(); ++i) + { + CPPUNIT_ASSERT_EQUAL( + sUserName[i], + static_cast<sal_Unicode>(static_cast<sal_Int16>(sLockFileContent[55 + i * 2]) + + static_cast<sal_Int16>(sLockFileContent[55 + i * 2 + 1]))); + } + + // We have some filling 0 bytes after the user name + for (nIndex += sUserName.getLength() * 2 + 1; nIndex < MSO_WORD_LOCKFILE_SIZE; ++nIndex) + { + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), static_cast<sal_Int32>(sLockFileContent[nIndex])); + } + + // We have a fixed size lock file + CPPUNIT_ASSERT_EQUAL(sal_Int32(MSO_WORD_LOCKFILE_SIZE), sLockFileContent.getLength()); +} + +void LockfileTest::testExcelLockFileContent() +{ + // Test the lockfile generated for the specified XLSX document + OUString aTestFile + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testExcelLockFileContent.xlsx"); + + // Set user name + SvtUserOptions aUserOpt; + aUserOpt.SetToken(UserOptToken::FirstName, "LockFile"); + aUserOpt.SetToken(UserOptToken::LastName, "Test"); + + // Write the lock file and check the content + svt::MSODocumentLockFile aLockFile(aTestFile); + aLockFile.CreateOwnLockFile(); + OUString sLockFileContent(readLockFile(aLockFile.GetURL())); + aLockFile.RemoveFileDirectly(); + + // First character is the size of the user name + OUString sUserName; + sUserName += aUserOpt.GetFirstName() + " "; + sUserName += aUserOpt.GetLastName(); + int nIndex = 0; + CPPUNIT_ASSERT_EQUAL(sUserName.getLength(), static_cast<sal_Int32>(sLockFileContent[nIndex])); + + // Then we have the user name + CPPUNIT_ASSERT_EQUAL(sUserName, sLockFileContent.copy(1, sUserName.getLength())); + + // We have some filling 0x20 bytes after the user name + for (nIndex = sUserName.getLength() + 1; nIndex < MSO_USERNAME_MAX_LENGTH + 3; ++nIndex) + { + CPPUNIT_ASSERT_EQUAL(sal_Int32(0x20), static_cast<sal_Int32>(sLockFileContent[nIndex])); + } + + // Then we have the user name's length again + CPPUNIT_ASSERT_EQUAL(sUserName.getLength(), static_cast<sal_Int32>(sLockFileContent[nIndex])); + + // Then we have the user name again with 16 bit coding + for (int i = 0; i < sUserName.getLength(); ++i) + { + CPPUNIT_ASSERT_EQUAL( + sUserName[i], + static_cast<sal_Unicode>(static_cast<sal_Int16>(sLockFileContent[56 + i * 2]) + + static_cast<sal_Int16>(sLockFileContent[56 + i * 2 + 1]))); + } + + // We have some filling 0 and 0x20 bytes after the user name + for (nIndex += sUserName.getLength() * 2 + 2; nIndex < MSO_EXCEL_AND_POWERPOINT_LOCKFILE_SIZE; + nIndex += 2) + { + CPPUNIT_ASSERT_EQUAL(sal_Int32(0x20), static_cast<sal_Int32>(sLockFileContent[nIndex])); + if (nIndex + 1 < MSO_EXCEL_AND_POWERPOINT_LOCKFILE_SIZE) + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), + static_cast<sal_Int32>(sLockFileContent[nIndex + 1])); + } + + // We have a fixed size lock file + CPPUNIT_ASSERT_EQUAL(sal_Int32(MSO_EXCEL_AND_POWERPOINT_LOCKFILE_SIZE), + sLockFileContent.getLength()); +} + +void LockfileTest::testPowerPointLockFileContent() +{ + // Test the lockfile generated for the specified PPTX document + OUString aTestFile = m_directories.getURLFromSrc( + "/svl/qa/unit/lockfiles/data/testPowerPointLockFileContent.pptx"); + + // Set user name + SvtUserOptions aUserOpt; + aUserOpt.SetToken(UserOptToken::FirstName, "LockFile"); + aUserOpt.SetToken(UserOptToken::LastName, "Test"); + + // Write the lock file and check the content + svt::MSODocumentLockFile aLockFile(aTestFile); + aLockFile.CreateOwnLockFile(); + OUString sLockFileContent(readLockFile(aLockFile.GetURL())); + aLockFile.RemoveFileDirectly(); + + // First character is the size of the user name + OUString sUserName; + sUserName += aUserOpt.GetFirstName() + " "; + sUserName += aUserOpt.GetLastName(); + int nIndex = 0; + CPPUNIT_ASSERT_EQUAL(sUserName.getLength(), static_cast<sal_Int32>(sLockFileContent[nIndex])); + + // Then we have the user name + CPPUNIT_ASSERT_EQUAL(sUserName, sLockFileContent.copy(1, sUserName.getLength())); + + // We have some filling bytes after the user name + nIndex = sUserName.getLength() + 1; + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), static_cast<sal_Int32>(sLockFileContent[nIndex])); + for (nIndex += 1; nIndex < MSO_USERNAME_MAX_LENGTH + 3; ++nIndex) + { + CPPUNIT_ASSERT_EQUAL(sal_Int32(0x20), static_cast<sal_Int32>(sLockFileContent[nIndex])); + } + + // Then we have the user name's length again + CPPUNIT_ASSERT_EQUAL(sUserName.getLength(), static_cast<sal_Int32>(sLockFileContent[nIndex])); + + // Then we have the user name again with 16 bit coding + for (int i = 0; i < sUserName.getLength(); ++i) + { + CPPUNIT_ASSERT_EQUAL( + sUserName[i], + static_cast<sal_Unicode>(static_cast<sal_Int16>(sLockFileContent[56 + i * 2]) + + static_cast<sal_Int16>(sLockFileContent[56 + i * 2 + 1]))); + } + + // We have some filling 0 and 0x20 bytes after the user name + for (nIndex += sUserName.getLength() * 2 + 2; nIndex < MSO_EXCEL_AND_POWERPOINT_LOCKFILE_SIZE; + nIndex += 2) + { + CPPUNIT_ASSERT_EQUAL(sal_Int32(0x20), static_cast<sal_Int32>(sLockFileContent[nIndex])); + if (nIndex + 1 < MSO_EXCEL_AND_POWERPOINT_LOCKFILE_SIZE) + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), + static_cast<sal_Int32>(sLockFileContent[nIndex + 1])); + } + + // We have a fixed size lock file + CPPUNIT_ASSERT_EQUAL(sal_Int32(MSO_EXCEL_AND_POWERPOINT_LOCKFILE_SIZE), + sLockFileContent.getLength()); +} + +void LockfileTest::testWordLockFileRT() +{ + OUString aTestODT + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testWordLockFileRT.docx"); + + // Set user name + SvtUserOptions aUserOpt; + aUserOpt.SetToken(UserOptToken::FirstName, "LockFile"); + aUserOpt.SetToken(UserOptToken::LastName, "Test"); + + // Write the lock file and read it back + svt::MSODocumentLockFile aLockFile(aTestODT); + LockFileEntry aOrigEntry = svt::LockFileCommon::GenerateOwnEntry(); + aLockFile.CreateOwnLockFile(); + LockFileEntry aRTEntry = aLockFile.GetLockData(); + aLockFile.RemoveFileDirectly(); + + // Check whether the lock file attributes are the same + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::OOOUSERNAME], + aRTEntry[LockFileComponent::OOOUSERNAME]); +} + +void LockfileTest::testExcelLockFileRT() +{ + OUString aTestODT + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testExcelLockFileRT.xlsx"); + + // Set user name + SvtUserOptions aUserOpt; + aUserOpt.SetToken(UserOptToken::FirstName, "LockFile"); + aUserOpt.SetToken(UserOptToken::LastName, "Test"); + + // Write the lock file and read it back + svt::MSODocumentLockFile aLockFile(aTestODT); + LockFileEntry aOrigEntry = svt::LockFileCommon::GenerateOwnEntry(); + aLockFile.CreateOwnLockFile(); + LockFileEntry aRTEntry = aLockFile.GetLockData(); + aLockFile.RemoveFileDirectly(); + + // Check whether the lock file attributes are the same + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::OOOUSERNAME], + aRTEntry[LockFileComponent::OOOUSERNAME]); +} + +void LockfileTest::testPowerPointLockFileRT() +{ + OUString aTestODT + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testPowerPointLockFileRT.pptx"); + + // Set user name + SvtUserOptions aUserOpt; + aUserOpt.SetToken(UserOptToken::FirstName, "LockFile"); + aUserOpt.SetToken(UserOptToken::LastName, "Test"); + + // Write the lock file and read it back + svt::MSODocumentLockFile aLockFile(aTestODT); + LockFileEntry aOrigEntry = svt::LockFileCommon::GenerateOwnEntry(); + aLockFile.CreateOwnLockFile(); + LockFileEntry aRTEntry = aLockFile.GetLockData(); + aLockFile.RemoveFileDirectly(); + + // Check whether the lock file attributes are the same + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::OOOUSERNAME], + aRTEntry[LockFileComponent::OOOUSERNAME]); +} + +void LockfileTest::testMSOLockFileLongUserName() +{ + OUString aTestODT = m_directories.getURLFromSrc( + "/svl/qa/unit/lockfiles/data/testMSOLockFileLongUserName.docx"); + + // Set user name + SvtUserOptions aUserOpt; + aUserOpt.SetToken(UserOptToken::FirstName, + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + aUserOpt.SetToken(UserOptToken::LastName, + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + + // Write the lock file and read it back + svt::MSODocumentLockFile aLockFile(aTestODT); + LockFileEntry aOrigEntry = svt::LockFileCommon::GenerateOwnEntry(); + aLockFile.CreateOwnLockFile(); + LockFileEntry aRTEntry = aLockFile.GetLockData(); + + // Check whether the user name was cut to the maximum length + CPPUNIT_ASSERT_EQUAL( + aOrigEntry[LockFileComponent::OOOUSERNAME].copy(0, MSO_USERNAME_MAX_LENGTH), + aRTEntry[LockFileComponent::OOOUSERNAME]); + + aLockFile.RemoveFileDirectly(); +} + +void LockfileTest::testMSOLockFileUnicodeUsername() +{ + // Test the lockfile generated for the specified ODT document + OUString aTestODT = m_directories.getURLFromSrc( + "/svl/qa/unit/lockfiles/data/testMSOLockFileUnicodeUsername.docx"); + + // Set user name + SvtUserOptions aUserOpt; + sal_Unicode vFirstName[] = { 2351, 2676, 3117, 5279 }; + aUserOpt.SetToken(UserOptToken::FirstName, OUString(vFirstName, 4)); + sal_Unicode vLastName[] = { 671, 1245, 1422, 1822 }; + aUserOpt.SetToken(UserOptToken::LastName, OUString(vLastName, 4)); + + // Write the lock file and read it back + svt::DocumentLockFile aLockFile(aTestODT); + LockFileEntry aOrigEntry = svt::LockFileCommon::GenerateOwnEntry(); + aLockFile.CreateOwnLockFile(); + LockFileEntry aRTEntry = aLockFile.GetLockData(); + + // Check whether the user name is the same + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::OOOUSERNAME], + aRTEntry[LockFileComponent::OOOUSERNAME]); + CPPUNIT_ASSERT_EQUAL(OUString(aUserOpt.GetFirstName() + " " + aUserOpt.GetLastName()), + aOrigEntry[LockFileComponent::OOOUSERNAME]); + + aLockFile.RemoveFileDirectly(); +} + +void LockfileTest::testMSOLockFileOverwrite() +{ + OUString aTestODT + = m_directories.getURLFromSrc("/svl/qa/unit/lockfiles/data/testMSOLockFileOverwrite.docx"); + + // Set user name + SvtUserOptions aUserOpt; + aUserOpt.SetToken(UserOptToken::FirstName, "LockFile"); + aUserOpt.SetToken(UserOptToken::LastName, "Test"); + + // Write the lock file and read it back + svt::MSODocumentLockFile aLockFile(aTestODT); + aLockFile.CreateOwnLockFile(); + + // Change user name + aUserOpt.SetToken(UserOptToken::FirstName, "LockFile2"); + aUserOpt.SetToken(UserOptToken::LastName, "Test"); + + // Overwrite lockfile + svt::MSODocumentLockFile aLockFile2(aTestODT); + LockFileEntry aOrigEntry = svt::LockFileCommon::GenerateOwnEntry(); + aLockFile2.OverwriteOwnLockFile(); + + LockFileEntry aRTEntry = aLockFile.GetLockData(); + + // Check whether the lock file attributes are the same + CPPUNIT_ASSERT_EQUAL(aOrigEntry[LockFileComponent::OOOUSERNAME], + aRTEntry[LockFileComponent::OOOUSERNAME]); + + aLockFile2.RemoveFileDirectly(); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(LockfileTest); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/svl/source/misc/documentlockfile.cxx b/svl/source/misc/documentlockfile.cxx index 837005bd6f85..1bdf7ce5f386 100644 --- a/svl/source/misc/documentlockfile.cxx +++ b/svl/source/misc/documentlockfile.cxx @@ -54,42 +54,34 @@ using namespace ::com::sun::star; namespace svt { -bool DocumentLockFile::m_bAllowInteraction = true; +GenDocumentLockFile::GenDocumentLockFile( const OUString& aURL ) +: LockFileCommon( aURL ) +{ +} -DocumentLockFile::DocumentLockFile( const OUString& aOrigURL ) -: LockFileCommon( aOrigURL, ".~lock." ) +GenDocumentLockFile::GenDocumentLockFile( const OUString& aOrigURL, const OUString& aPrefix ) +: LockFileCommon( aOrigURL, aPrefix ) { } -DocumentLockFile::~DocumentLockFile() +GenDocumentLockFile::~GenDocumentLockFile() { } - -void DocumentLockFile::WriteEntryToStream( const LockFileEntry& aEntry, const uno::Reference< io::XOutputStream >& xOutput ) +uno::Reference< io::XInputStream > GenDocumentLockFile::OpenStream() { ::osl::MutexGuard aGuard( m_aMutex ); - OUStringBuffer aBuffer; - - for ( LockFileComponent lft : o3tl::enumrange<LockFileComponent>() ) - { - aBuffer.append( EscapeCharacters( aEntry[lft] ) ); - if ( lft < LockFileComponent::LAST ) - aBuffer.append( ',' ); - else - aBuffer.append( ';' ); - } + uno::Reference < css::ucb::XCommandEnvironment > xEnv; + ::ucbhelper::Content aSourceContent( GetURL(), xEnv, comphelper::getProcessComponentContext() ); - OString aStringData( OUStringToOString( aBuffer.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ) ); - uno::Sequence< sal_Int8 > aData( reinterpret_cast<sal_Int8 const *>(aStringData.getStr()), aStringData.getLength() ); - xOutput->writeBytes( aData ); + // the file can be opened readonly, no locking will be done + return aSourceContent.openStream(); } - -bool DocumentLockFile::CreateOwnLockFile() +bool GenDocumentLockFile::CreateOwnLockFile() { ::osl::MutexGuard aGuard( m_aMutex ); @@ -113,7 +105,7 @@ bool DocumentLockFile::CreateOwnLockFile() xSeekable->seek( 0 ); uno::Reference < css::ucb::XCommandEnvironment > xEnv; - ::ucbhelper::Content aTargetContent( m_aURL, xEnv, comphelper::getProcessComponentContext() ); + ::ucbhelper::Content aTargetContent( GetURL(), xEnv, comphelper::getProcessComponentContext() ); ucb::InsertCommandArgument aInsertArg; aInsertArg.Data = xInput; @@ -135,50 +127,13 @@ bool DocumentLockFile::CreateOwnLockFile() return true; } - -LockFileEntry DocumentLockFile::GetLockData() -{ - ::osl::MutexGuard aGuard( m_aMutex ); - - uno::Reference< io::XInputStream > xInput = OpenStream(); - if ( !xInput.is() ) - throw uno::RuntimeException(); - - const sal_Int32 nBufLen = 32000; - uno::Sequence< sal_Int8 > aBuffer( nBufLen ); - - sal_Int32 nRead = 0; - - nRead = xInput->readBytes( aBuffer, nBufLen ); - xInput->closeInput(); - - if ( nRead == nBufLen ) - throw io::WrongFormatException(); - - sal_Int32 nCurPos = 0; - return ParseEntry( aBuffer, nCurPos ); -} - - -uno::Reference< io::XInputStream > DocumentLockFile::OpenStream() -{ - ::osl::MutexGuard aGuard( m_aMutex ); - - uno::Reference < css::ucb::XCommandEnvironment > xEnv; - ::ucbhelper::Content aSourceContent( m_aURL, xEnv, comphelper::getProcessComponentContext() ); - - // the file can be opened readonly, no locking will be done - return aSourceContent.openStream(); -} - - -bool DocumentLockFile::OverwriteOwnLockFile() +bool GenDocumentLockFile::OverwriteOwnLockFile() { // allows to overwrite the lock file with the current data try { uno::Reference < css::ucb::XCommandEnvironment > xEnv; - ::ucbhelper::Content aTargetContent( m_aURL, xEnv, comphelper::getProcessComponentContext() ); + ::ucbhelper::Content aTargetContent( GetURL(), xEnv, comphelper::getProcessComponentContext() ); LockFileEntry aNewEntry = GenerateOwnEntry(); @@ -198,8 +153,7 @@ bool DocumentLockFile::OverwriteOwnLockFile() return true; } - -void DocumentLockFile::RemoveFile() +void GenDocumentLockFile::RemoveFile() { ::osl::MutexGuard aGuard( m_aMutex ); ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
