summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLászló Németh <nemeth@numbertext.org>2018-06-20 16:28:13 +0200
committerMiklos Vajna <vmiklos@collabora.co.uk>2018-07-18 15:39:57 +0200
commit61aaefd8e902f86f5f7347efdb56686638149133 (patch)
tree59457547e3247391d664d22413b2fbf6cad55084
parent88abae93c5e0a030eca36d7e33909ad52e1c71a2 (diff)
tdf#107690 OOXML import/export of setting "Open as read-only"
Import custom document property _MarkAsFinal as LoadReadonly setting, export LoadReadonly as _MarkAsFinal in DOCX, XLSX and PPTX documents. Before this fix, LibreOffice opened read-only OOXML documents as editable, also saved and exported _MarkAsFinal=true silently, resulting unintented read-only warning info bar in MSO. This commit improves interoperability a lot, because this is a basic document protection of MSO, recommended on its UI. Note: LoadReadonly (on File->Properties...->Security, property "Open file read-only") doesn't show "Edit read-only" info bar from commit 630186ff4e0eba7317e542f8c3eca39ebd068721, but it's still possible to switch on editing by Edit->Edit Mode. MSO shows info bar for _MarkAsFinal. (There is an advantage to hide the info bar in LibreOffice in a mixed environment, to avoid overwriting of press-ready MSO files by LibreOffice.) Note 2: Other differences of LoadReadonly in LO and _MarkAsFinal in MSO: (1) Switching on editing doesn't remove the LoadReadonly property automatically in LO. (2) Saving with LoadReadonly doesn't switch off editing of the actual (still opened) document in LO. (cherry picked from commit 9a5c56a9c4e04589b0a6bb710573922e459d9685 and bbdb6cb8ed0d77eeb2e413b38f29d2084bd8257b (unit tests)) Change-Id: I79897605e1fabe0708cce0b0c6216c152b201fc9 Reviewed-on: https://gerrit.libreoffice.org/56752 Tested-by: Jenkins Reviewed-by: László Németh <nemeth@numbertext.org> Tested-by: László Németh <nemeth@numbertext.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
-rw-r--r--include/oox/core/xmlfilterbase.hxx2
-rw-r--r--oox/source/core/xmlfilterbase.cxx50
-rw-r--r--sc/qa/unit/data/xlsx/open-as-read-only.xlsxbin0 -> 5211 bytes
-rw-r--r--sc/qa/unit/subsequent_export-test.cxx12
-rw-r--r--sc/source/filter/excel/excdoc.cxx2
-rw-r--r--sd/qa/unit/data/pptx/open-as-read-only.pptxbin0 -> 21569 bytes
-rw-r--r--sd/qa/unit/export-tests-ooxml2.cxx12
-rw-r--r--sd/source/filter/eppt/pptx-epptooxml.cxx14
-rw-r--r--sfx2/source/doc/objstor.cxx27
-rw-r--r--sw/qa/extras/ooxmlexport/data/open-as-read-only.docxbin0 -> 4594 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport11.cxx7
-rw-r--r--sw/source/filter/ww8/docxexport.cxx4
12 files changed, 111 insertions, 19 deletions
diff --git a/include/oox/core/xmlfilterbase.hxx b/include/oox/core/xmlfilterbase.hxx
index ffe0c5bc45e3..e2be8d14f9c8 100644
--- a/include/oox/core/xmlfilterbase.hxx
+++ b/include/oox/core/xmlfilterbase.hxx
@@ -224,7 +224,7 @@ public:
@param xProperties The document properties to export.
*/
- void exportDocumentProperties( const css::uno::Reference< css::document::XDocumentProperties >& xProperties );
+ void exportDocumentProperties( const css::uno::Reference< css::document::XDocumentProperties >& xProperties, bool bSecurityOptOpenReadOnly );
/** Write the customXml entries we are preserving (xlsx and pptx only). */
void exportCustomFragments();
diff --git a/oox/source/core/xmlfilterbase.cxx b/oox/source/core/xmlfilterbase.cxx
index 57a752489960..5168d81fb7fb 100644
--- a/oox/source/core/xmlfilterbase.cxx
+++ b/oox/source/core/xmlfilterbase.cxx
@@ -750,13 +750,31 @@ writeAppProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties >
}
static void
-writeCustomProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties >& xProperties )
+writeCustomProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties >& xProperties, bool bSecurityOptOpenReadOnly )
{
uno::Reference<beans::XPropertyAccess> xUserDefinedProperties( xProperties->getUserDefinedProperties(), uno::UNO_QUERY );
Sequence< PropertyValue > aprop( xUserDefinedProperties->getPropertyValues() );
sal_Int32 nbCustomProperties = aprop.getLength();
// tdf#89791 : if no custom properties, no need to add docProps/custom.x
- if (!nbCustomProperties)
+ // tdf#107690: except the case of read-only documents, because that
+ // is handled by the _MarkAsFinal custom property in MSO.
+ if (!nbCustomProperties && !bSecurityOptOpenReadOnly)
+ return;
+
+ std::vector<PropertyValue> aprop2;
+ for ( sal_Int32 n = 0; n < nbCustomProperties; ++n )
+ aprop2.push_back(aprop[n]);
+
+ if (bSecurityOptOpenReadOnly)
+ {
+ PropertyValue aPropertyValue;
+ // MSO custom property for read-only documents
+ aPropertyValue.Name = "_MarkAsFinal";
+ aPropertyValue.Value <<= true;
+ aprop2.push_back(aPropertyValue);
+ }
+
+ if (!aprop2.size())
return;
rSelf.addRelation(
@@ -770,11 +788,12 @@ writeCustomProperties( XmlFilterBase& rSelf, const Reference< XDocumentPropertie
FSNS( XML_xmlns, XML_vt ), OUStringToOString(rSelf.getNamespaceURL(OOX_NS(officeDocPropsVT)), RTL_TEXTENCODING_UTF8).getStr(),
FSEND );
- for ( sal_Int32 n = 0; n < nbCustomProperties; ++n )
+ auto aIt = aprop2.begin();
+ for ( size_t n = 0; n < aprop2.size(); ++n )
{
- if ( !aprop[n].Name.isEmpty() )
+ if ( !aIt->Name.isEmpty() )
{
- OString aName = OUStringToOString( aprop[n].Name, RTL_TEXTENCODING_ASCII_US );
+ OString aName = OUStringToOString( aIt->Name, RTL_TEXTENCODING_ASCII_US );
// pid starts from 2 not from 1 as MS supports pid from 2
pAppProps->startElement( XML_property ,
XML_fmtid, "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",
@@ -782,18 +801,18 @@ writeCustomProperties( XmlFilterBase& rSelf, const Reference< XDocumentPropertie
XML_name, aName,
FSEND);
- switch ( aprop[n].Value.getValueTypeClass() )
+ switch ( aIt->Value.getValueTypeClass() )
{
case TypeClass_STRING:
{
OUString aValue;
- aprop[n].Value >>= aValue;
- writeElement( pAppProps, FSNS( XML_vt, XML_lpwstr ), aValue );
+ aIt->Value >>= aValue;
+ writeElement( pAppProps, FSNS( XML_vt, XML_lpwstr ), aValue );
}
break;
case TypeClass_BOOLEAN:
{
- bool val = *o3tl::forceAccess<bool>(aprop[n].Value);
+ bool val = *o3tl::forceAccess<bool>(aIt->Value);
writeElement( pAppProps, FSNS( XML_vt, XML_bool ), val ? 1 : 0);
}
break;
@@ -803,23 +822,23 @@ writeCustomProperties( XmlFilterBase& rSelf, const Reference< XDocumentPropertie
util::Date aDate;
util::Duration aDuration;
util::DateTime aDateTime;
- if ( ( aprop[n].Value ) >>= num )
+ if ( ( aIt->Value ) >>= num )
{
writeElement( pAppProps, FSNS( XML_vt, XML_i4 ), num );
}
- else if ( ( aprop[n].Value ) >>= aDate )
+ else if ( ( aIt->Value ) >>= aDate )
{
aDateTime = util::DateTime( 0, 0 , 0, 0, aDate.Year, aDate.Month, aDate.Day, true );
writeElement( pAppProps, FSNS( XML_vt, XML_filetime ), aDateTime);
}
- else if ( ( aprop[n].Value ) >>= aDuration )
+ else if ( ( aIt->Value ) >>= aDuration )
{
OUStringBuffer buf;
::sax::Converter::convertDuration( buf, aDuration );
OUString aDurationStr = buf.makeStringAndClear();
writeElement( pAppProps, FSNS( XML_vt, XML_lpwstr ), aDurationStr );
}
- else if ( ( aprop[n].Value ) >>= aDateTime )
+ else if ( ( aIt->Value ) >>= aDateTime )
writeElement( pAppProps, FSNS( XML_vt, XML_filetime ), aDateTime );
else
//no other options
@@ -829,17 +848,18 @@ writeCustomProperties( XmlFilterBase& rSelf, const Reference< XDocumentPropertie
}
pAppProps->endElement( XML_property );
}
+ ++aIt;
}
pAppProps->endElement( XML_Properties );
}
-void XmlFilterBase::exportDocumentProperties( const Reference< XDocumentProperties >& xProperties )
+void XmlFilterBase::exportDocumentProperties( const Reference< XDocumentProperties >& xProperties, bool bSecurityOptOpenReadOnly )
{
if( xProperties.is() )
{
writeCoreProperties( *this, xProperties );
writeAppProperties( *this, xProperties );
- writeCustomProperties( *this, xProperties );
+ writeCustomProperties( *this, xProperties, bSecurityOptOpenReadOnly );
}
}
diff --git a/sc/qa/unit/data/xlsx/open-as-read-only.xlsx b/sc/qa/unit/data/xlsx/open-as-read-only.xlsx
new file mode 100644
index 000000000000..e871a95d3997
--- /dev/null
+++ b/sc/qa/unit/data/xlsx/open-as-read-only.xlsx
Binary files differ
diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx
index 5e65134fbfbe..e7440a249da8 100644
--- a/sc/qa/unit/subsequent_export-test.cxx
+++ b/sc/qa/unit/subsequent_export-test.cxx
@@ -204,6 +204,7 @@ public:
void testHiddenRepeatedRowsODS();
void testHyperlinkTargetFrameODS();
+ void testOpenDocumentAsReadOnly();
CPPUNIT_TEST_SUITE(ScExportTest);
CPPUNIT_TEST(test);
@@ -309,6 +310,7 @@ public:
CPPUNIT_TEST(testHiddenRepeatedRowsODS);
CPPUNIT_TEST(testHyperlinkTargetFrameODS);
+ CPPUNIT_TEST(testOpenDocumentAsReadOnly);
CPPUNIT_TEST_SUITE_END();
@@ -3994,6 +3996,16 @@ void ScExportTest::testHyperlinkTargetFrameODS()
CPPUNIT_ASSERT_EQUAL(OUString("_blank"), aTargetFrameExport);
}
+void ScExportTest::testOpenDocumentAsReadOnly()
+{
+ ScDocShellRef xDocSh = loadDoc("open-as-read-only.", FORMAT_XLSX);
+ CPPUNIT_ASSERT(xDocSh->IsSecurityOptOpenReadOnly());
+ ScDocShellRef xDocSh2 = saveAndReload(xDocSh.get(), FORMAT_XLSX);
+ CPPUNIT_ASSERT(xDocSh2->IsSecurityOptOpenReadOnly());
+ xDocSh->DoClose();
+ xDocSh2->DoClose();
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/source/filter/excel/excdoc.cxx b/sc/source/filter/excel/excdoc.cxx
index e2b30c261837..891919fdc7e7 100644
--- a/sc/source/filter/excel/excdoc.cxx
+++ b/sc/source/filter/excel/excdoc.cxx
@@ -828,7 +828,7 @@ void ExcDocument::WriteXml( XclExpXmlStream& rStrm )
uno::Reference<document::XDocumentPropertiesSupplier> xDPS( pDocShell->GetModel(), uno::UNO_QUERY_THROW );
uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties();
- rStrm.exportDocumentProperties(xDocProps);
+ rStrm.exportDocumentProperties(xDocProps, pDocShell->IsSecurityOptOpenReadOnly());
rStrm.exportCustomFragments();
sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
diff --git a/sd/qa/unit/data/pptx/open-as-read-only.pptx b/sd/qa/unit/data/pptx/open-as-read-only.pptx
new file mode 100644
index 000000000000..57a4d32de7f4
--- /dev/null
+++ b/sd/qa/unit/data/pptx/open-as-read-only.pptx
Binary files differ
diff --git a/sd/qa/unit/export-tests-ooxml2.cxx b/sd/qa/unit/export-tests-ooxml2.cxx
index c0b23ac38cdd..92258796d507 100644
--- a/sd/qa/unit/export-tests-ooxml2.cxx
+++ b/sd/qa/unit/export-tests-ooxml2.cxx
@@ -143,6 +143,7 @@ public:
void testTdf90627();
void testTdf104786();
void testTdf104789();
+ void testOpenDocumentAsReadOnly();
CPPUNIT_TEST_SUITE(SdOOXMLExportTest2);
@@ -209,6 +210,7 @@ public:
CPPUNIT_TEST(testTdf90627);
CPPUNIT_TEST(testTdf104786);
CPPUNIT_TEST(testTdf104789);
+ CPPUNIT_TEST(testOpenDocumentAsReadOnly);
CPPUNIT_TEST_SUITE_END();
@@ -1677,6 +1679,16 @@ void SdOOXMLExportTest2::testTdf104789()
xDocShRef->DoClose();
}
+void SdOOXMLExportTest2::testOpenDocumentAsReadOnly()
+{
+ ::sd::DrawDocShellRef xDocShRef = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/pptx/open-as-read-only.pptx"), PPTX);
+ CPPUNIT_ASSERT(xDocShRef->IsSecurityOptOpenReadOnly());
+ utl::TempFile tempFile;
+ xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
+ CPPUNIT_ASSERT(xDocShRef->IsSecurityOptOpenReadOnly());
+ xDocShRef->DoClose();
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(SdOOXMLExportTest2);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx
index 13dd072460f0..d90ea3a60d7b 100644
--- a/sd/source/filter/eppt/pptx-epptooxml.cxx
+++ b/sd/source/filter/eppt/pptx-epptooxml.cxx
@@ -357,7 +357,19 @@ void PowerPointExport::writeDocumentProperties()
uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties();
if (xDocProps.is())
- exportDocumentProperties(xDocProps);
+ {
+ bool bSecurityOptOpenReadOnly = false;
+ uno::Reference< lang::XMultiServiceFactory > xFactory(mXModel, uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySet > xSettings(xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
+ try
+ {
+ xSettings->getPropertyValue("LoadReadonly") >>= bSecurityOptOpenReadOnly;
+ }
+ catch( Exception& )
+ {
+ }
+ exportDocumentProperties(xDocProps, bSecurityOptOpenReadOnly);
+ }
exportCustomFragments();
}
diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx
index 7f34e6a9ca96..716455cda9ae 100644
--- a/sfx2/source/doc/objstor.cxx
+++ b/sfx2/source/doc/objstor.cxx
@@ -2247,6 +2247,33 @@ bool SfxObjectShell::ImportFrom(SfxMedium& rMedium,
}
}
}
+
+ // tdf#107690 import custom document property _MarkAsFinal as SecurityOptOpenReadonly
+ // (before this fix, LibreOffice opened read-only OOXML documents as editable,
+ // also saved and exported _MarkAsFinal=true silently, resulting unintented read-only
+ // warning info bar in MSO)
+ uno::Reference< document::XDocumentPropertiesSupplier > xPropSupplier(GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps = xPropSupplier->getDocumentProperties() ;
+ uno::Reference<beans::XPropertyContainer> xPropertyContainer = xDocProps->getUserDefinedProperties();
+ if (xPropertyContainer.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xPropertyContainer, uno::UNO_QUERY);
+ if (xPropertySet.is())
+ {
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
+ if (xPropertySetInfo.is() && xPropertySetInfo->hasPropertyByName("_MarkAsFinal"))
+ {
+ if (xPropertySet->getPropertyValue("_MarkAsFinal").get<bool>())
+ {
+ uno::Reference< lang::XMultiServiceFactory > xFactory(GetModel(), uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySet > xSettings(xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
+ xSettings->setPropertyValue("LoadReadonly", uno::makeAny(true));
+ }
+ xPropertyContainer->removeProperty("_MarkAsFinal");
+ }
+ }
+ }
+
return bRtn;
}
catch (const packages::zip::ZipIOException&)
diff --git a/sw/qa/extras/ooxmlexport/data/open-as-read-only.docx b/sw/qa/extras/ooxmlexport/data/open-as-read-only.docx
new file mode 100644
index 000000000000..057c67ff6dfe
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/open-as-read-only.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
index 9882bb943f7b..f27c88facc67 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
@@ -394,6 +394,13 @@ DECLARE_OOXMLEXPORT_TEST(testTdf107969, "tdf107969.docx")
// SAXParseException: '[word/document.xml line 2]: Extra content at the end of the document', Stream 'word/document.xml'.
}
+DECLARE_OOXMLEXPORT_TEST(testOpenDocumentAsReadOnly, "open-as-read-only.docx")
+{
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ CPPUNIT_ASSERT(pTextDoc->GetDocShell()->IsSecurityOptOpenReadOnly());
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index 68a04ba937d7..6199cbf94acd 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -887,14 +887,16 @@ void DocxExport::WriteProperties( )
// Write the core properties
SwDocShell* pDocShell( m_pDoc->GetDocShell( ) );
uno::Reference<document::XDocumentProperties> xDocProps;
+ bool bSecurityOptOpenReadOnly = false;
if ( pDocShell )
{
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
pDocShell->GetModel( ), uno::UNO_QUERY );
xDocProps = xDPS->getDocumentProperties();
+ bSecurityOptOpenReadOnly = pDocShell->IsSecurityOptOpenReadOnly();
}
- m_pFilter->exportDocumentProperties( xDocProps );
+ m_pFilter->exportDocumentProperties( xDocProps, bSecurityOptOpenReadOnly );
}
void DocxExport::WriteSettings()