summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLászló Németh <nemeth@numbertext.org>2018-06-20 16:28:13 +0200
committerLászló Németh <nemeth@numbertext.org>2018-06-28 16:34:52 +0200
commit9a5c56a9c4e04589b0a6bb710573922e459d9685 (patch)
treece22578a4ca4992bdf64c18f1012dd515540ebfa
parent9c368751f6fbc50209e621182c3415ef4c4db29d (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. Change-Id: Ie279c0670090d075103384cfa44ff1c2a2898216 Reviewed-on: https://gerrit.libreoffice.org/56180 Tested-by: Jenkins Reviewed-by: László Németh <nemeth@numbertext.org>
-rw-r--r--include/oox/core/xmlfilterbase.hxx2
-rw-r--r--oox/source/core/xmlfilterbase.cxx50
-rw-r--r--sc/source/filter/excel/excdoc.cxx2
-rw-r--r--sd/source/filter/eppt/pptx-epptooxml.cxx14
-rw-r--r--sfx2/source/doc/objstor.cxx27
-rw-r--r--sw/source/filter/ww8/docxexport.cxx4
6 files changed, 80 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/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/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx
index 59da0d6932c4..212821d7b56b 100644
--- a/sd/source/filter/eppt/pptx-epptooxml.cxx
+++ b/sd/source/filter/eppt/pptx-epptooxml.cxx
@@ -362,7 +362,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 9bc418f8f53a..f0fbca97941c 100644
--- a/sfx2/source/doc/objstor.cxx
+++ b/sfx2/source/doc/objstor.cxx
@@ -2248,6 +2248,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/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index 9355677fed3c..c3bf421ef793 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -886,14 +886,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()