summaryrefslogtreecommitdiff
path: root/oox
diff options
context:
space:
mode:
authorBartosz Kosiorek <gang65@poczta.onet.pl>2020-10-15 19:57:45 +0200
committerBartosz Kosiorek <gang65@poczta.onet.pl>2020-10-22 14:42:27 +0200
commita87af93ff874a55b81e55b46b63798fde4cefc4f (patch)
treed2fc3f044c06e522bcb8ee8cdeb5dce532ff7286 /oox
parentcb310560a887ba08ea4234ea6cdd217151ca0728 (diff)
tdf#103987 Avoid duplication of the Custom Properties during OOXML export
The MS Office is case insensitive for Properties. As a result properties names: ContentType and contentType are treated as the same properties. Additionally some Core and Extended File Properties does not exist in LibreOffice standard. To resolve that such properties are stored in LibreOffice Custom File Properties. For example: - category - contentStatus - contentType - identifier - version Unfortunately if user specify Custom Property which differ only with case, there will be conflict. To solve that the properties were renamed to be unique: - OOXMLCorePropertiesCategory - OOXMLCorePropertiesContentStatus - OOXMLCorePropertiesContentType - OOXMLCorePropertiesIdentifier - OOXMLCorePropertiesVersion Additionally if internal property have default value, then the value will not be imported into Custom File Property. During export to OOXML (eg. docx) The values which are already stored in Core or Extended File Properties, are not stored into Custom File Properties to avoid duplication. Change-Id: Ifc2b88ab74aa41d12ba968fff199062ce8dc96ee Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104384 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@cib.de> Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
Diffstat (limited to 'oox')
-rw-r--r--oox/source/core/xmlfilterbase.cxx126
-rw-r--r--oox/source/docprop/docprophandler.cxx51
2 files changed, 140 insertions, 37 deletions
diff --git a/oox/source/core/xmlfilterbase.cxx b/oox/source/core/xmlfilterbase.cxx
index 43f4e573229a..259e0bf2e406 100644
--- a/oox/source/core/xmlfilterbase.cxx
+++ b/oox/source/core/xmlfilterbase.cxx
@@ -640,17 +640,44 @@ writeCoreProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties
FSNS(XML_xmlns, XML_dcmitype), rSelf.getNamespaceURL(OOX_NS(dcmiType)),
FSNS(XML_xmlns, XML_xsi), rSelf.getNamespaceURL(OOX_NS(xsi)));
-#ifdef OOXTODO
- writeElement( pCoreProps, FSNS( XML_cp, XML_category ), "category" );
- writeElement( pCoreProps, FSNS( XML_cp, XML_contentStatus ), "status" );
- writeElement( pCoreProps, FSNS( XML_cp, XML_contentType ), "contentType" );
-#endif /* def OOXTODO */
+ uno::Reference<beans::XPropertyAccess> xUserDefinedProperties(xProperties->getUserDefinedProperties(), uno::UNO_QUERY);
+ comphelper::SequenceAsHashMap aUserDefinedProperties(xUserDefinedProperties->getPropertyValues());
+ comphelper::SequenceAsHashMap::iterator it;
+
+ it = aUserDefinedProperties.find("OOXMLCorePropertyCategory");
+ if (it != aUserDefinedProperties.end())
+ {
+ OUString aValue;
+ if (it->second >>= aValue)
+ writeElement( pCoreProps, FSNS( XML_cp, XML_category ), aValue );
+ }
+
+ it = aUserDefinedProperties.find("OOXMLCorePropertyContentStatus");
+ if (it != aUserDefinedProperties.end())
+ {
+ OUString aValue;
+ if (it->second >>= aValue)
+ writeElement( pCoreProps, FSNS( XML_cp, XML_contentStatus ), aValue );
+ }
+
+ it = aUserDefinedProperties.find("OOXMLCorePropertyContentType");
+ if (it != aUserDefinedProperties.end())
+ {
+ OUString aValue;
+ if (it->second >>= aValue)
+ writeElement( pCoreProps, FSNS( XML_cp, XML_contentType ), aValue );
+ }
writeElement( pCoreProps, FSNS( XML_dcterms, XML_created ), xProperties->getCreationDate() );
writeElement( pCoreProps, FSNS( XML_dc, XML_creator ), xProperties->getAuthor() );
writeElement( pCoreProps, FSNS( XML_dc, XML_description ), xProperties->getDescription() );
-#ifdef OOXTODO
- writeElement( pCoreProps, FSNS( XML_dc, XML_identifier ), "ident" );
-#endif /* def OOXTODO */
+
+ it = aUserDefinedProperties.find("OOXMLCorePropertyIdentifier");
+ if (it != aUserDefinedProperties.end())
+ {
+ OUString aValue;
+ if (it->second >>= aValue)
+ writeElement( pCoreProps, FSNS( XML_dc, XML_identifier ), aValue );
+ }
writeElement( pCoreProps, FSNS( XML_cp, XML_keywords ), xProperties->getKeywords() );
writeElement( pCoreProps, FSNS( XML_dc, XML_language ), LanguageTag( xProperties->getLanguage()) );
writeElement( pCoreProps, FSNS( XML_cp, XML_lastModifiedBy ), xProperties->getModifiedBy() );
@@ -659,9 +686,14 @@ writeCoreProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties
writeElement( pCoreProps, FSNS( XML_cp, XML_revision ), xProperties->getEditingCycles() );
writeElement( pCoreProps, FSNS( XML_dc, XML_subject ), xProperties->getSubject() );
writeElement( pCoreProps, FSNS( XML_dc, XML_title ), xProperties->getTitle() );
-#ifdef OOXTODO
- writeElement( pCoreProps, FSNS( XML_cp, XML_version ), "version" );
-#endif /* def OOXTODO */
+
+ it = aUserDefinedProperties.find("OOXMLCorePropertyVersion");
+ if (it != aUserDefinedProperties.end())
+ {
+ OUString aValue;
+ if (it->second >>= aValue)
+ writeElement( pCoreProps, FSNS( XML_cp, XML_version ), aValue );
+ }
pCoreProps->endElementNS( XML_cp, XML_coreProperties );
}
@@ -679,9 +711,21 @@ writeAppProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties >
XML_xmlns, rSelf.getNamespaceURL(OOX_NS(officeExtPr)),
FSNS(XML_xmlns, XML_vt), rSelf.getNamespaceURL(OOX_NS(officeDocPropsVT)));
+ uno::Reference<beans::XPropertyAccess> xUserDefinedProperties(xProperties->getUserDefinedProperties(), uno::UNO_QUERY);
+ comphelper::SequenceAsHashMap aUserDefinedProperties(xUserDefinedProperties->getPropertyValues());
+ comphelper::SequenceAsHashMap::iterator it;
+
writeElement( pAppProps, XML_Template, xProperties->getTemplateName() );
+
+ it = aUserDefinedProperties.find("Manager");
+ if (it != aUserDefinedProperties.end())
+ {
+ OUString aValue;
+ if (it->second >>= aValue)
+ writeElement( pAppProps, XML_Manager, aValue );
+ }
+
#ifdef OOXTODO
- writeElement( pAppProps, XML_Manager, "manager" );
writeElement( pAppProps, XML_PresentationFormat, "presentation format" );
writeElement( pAppProps, XML_Lines, "lines" );
writeElement( pAppProps, XML_Slides, "slides" );
@@ -697,19 +741,37 @@ writeAppProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties >
writeElement( pAppProps, XML_TitlesOfParts, "titles of parts" );
writeElement( pAppProps, XML_LinksUpToDate, "links up-to-date" );
writeElement( pAppProps, XML_SharedDoc, "shared doc" );
- writeElement( pAppProps, XML_HyperlinkBase, "hyperlink base" );
writeElement( pAppProps, XML_HLinks, "hlinks" );
writeElement( pAppProps, XML_HyperlinksChanged, "hyperlinks changed" );
writeElement( pAppProps, XML_DigSig, "digital signature" );
#endif /* def OOXTODO */
writeElement( pAppProps, XML_Application, utl::DocInfoHelper::GetGeneratorString() );
-#ifdef OOXTODO
- writeElement( pAppProps, XML_AppVersion, "app version" );
- writeElement( pAppProps, XML_DocSecurity, "doc security" );
-#endif /* def OOXTODO */
+
+ it = aUserDefinedProperties.find("HyperlinkBase");
+ if (it != aUserDefinedProperties.end())
+ {
+ OUString aValue;
+ if (it->second >>= aValue)
+ writeElement( pAppProps, XML_HyperlinkBase, aValue );
+ }
+ // AppVersion specifies the version of the application which produced document
+ // It is strictly connected with MS Office versions:
+ // * 12: [Office 2007] [LO < 7.0]
+ // * 14: [Office 2010]
+ // * 15: [Office 2013/2016/2019] [LO >= 7.0]
+ // The LibreOffice is application on 2013/2016/2019 level
+ writeElement( pAppProps, XML_AppVersion, "15.0000" );
+
+ // OOXTODO Calculate DocSecurity value based on security (password, read-only etc.)
+ it = aUserDefinedProperties.find("DocSecurity");
+ if (it != aUserDefinedProperties.end())
+ {
+ sal_Int32 nValue;
+ if (it->second >>= nValue)
+ writeElement( pAppProps, XML_DocSecurity, nValue );
+ }
comphelper::SequenceAsHashMap aStats = xProperties->getDocumentStatistics();
- comphelper::SequenceAsHashMap::iterator it;
sal_Int32 nValue = 0;
it = aStats.find("PageCount");
@@ -747,8 +809,6 @@ writeAppProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties >
writeElement(pAppProps, XML_Paragraphs, nValue);
}
- uno::Reference<beans::XPropertyAccess> xUserDefinedProperties(xProperties->getUserDefinedProperties(), uno::UNO_QUERY);
- comphelper::SequenceAsHashMap aUserDefinedProperties(xUserDefinedProperties->getPropertyValues());
it = aUserDefinedProperties.find("Company");
if (it != aUserDefinedProperties.end())
{
@@ -797,6 +857,19 @@ writeCustomProperties( XmlFilterBase& rSelf, const Reference< XDocumentPropertie
if ( !rProp.Name.isEmpty() )
{
OString aName = OUStringToOString( rProp.Name, RTL_TEXTENCODING_ASCII_US );
+ // Skip storing these values in Custom Properties as it will be stored in Core/Extended Properties
+ if (( aName == "OOXMLCorePropertyCategory" ) || // stored in cp:category
+ ( aName == "OOXMLCorePropertyContentStatus" ) || // stored in cp:contentStatus
+ ( aName == "OOXMLCorePropertyContentType" ) || // stored in cp:contentType
+ ( aName == "OOXMLCorePropertyIdentifier" ) || // stored in dc:identifier
+ ( aName == "OOXMLCorePropertyVersion" ) || // stored in cp:version
+ ( aName == "HyperlinkBase" ) || // stored in Extended File Properties
+ ( aName == "AppVersion" ) || // stored in Extended File Properties
+ ( aName == "DocSecurity" ) || // stored in Extended File Properties
+ ( aName == "Manager" ) || // stored in Extended File Properties
+ ( aName == "Company" )) // stored in Extended File Properties
+ continue;
+
// pid starts from 2 not from 1 as MS supports pid from 2
pAppProps->startElement( XML_property ,
XML_fmtid, "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",
@@ -818,16 +891,25 @@ writeCustomProperties( XmlFilterBase& rSelf, const Reference< XDocumentPropertie
writeElement( pAppProps, FSNS( XML_vt, XML_bool ), val ? 1 : 0);
}
break;
+ case TypeClass_DOUBLE:
+ {
+ double num = {}; // spurious -Werror=maybe-uninitialized
+ if ( rProp.Value >>= num )
+ {
+ // r8 - 8-byte real number
+ writeElement( pAppProps, FSNS( XML_vt, XML_r8 ), OUString::number(num) );
+ }
+ }
+ break;
default:
{
- double num;
+ double num = {}; // spurious -Werror=maybe-uninitialized
util::Date aDate;
util::Duration aDuration;
util::DateTime aDateTime;
if ( rProp.Value >>= num )
{
// i4 - 4-byte signed integer
- // r8 - 8-byte real number
writeElement( pAppProps, FSNS( XML_vt, XML_i4 ), num );
}
else if ( rProp.Value >>= aDate )
diff --git a/oox/source/docprop/docprophandler.cxx b/oox/source/docprop/docprophandler.cxx
index e26db66b12c6..07f9b4c0dc72 100644
--- a/oox/source/docprop/docprophandler.cxx
+++ b/oox/source/docprop/docprophandler.cxx
@@ -414,27 +414,27 @@ void SAL_CALL OOXMLDocPropHandler::characters( const OUString& aChars )
switch( m_nBlock )
{
case COREPR_TOKEN( category ):
- m_aCustomPropertyName = "category";
+ m_aCustomPropertyName = "OOXMLCorePropertyCategory";
AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
break;
case COREPR_TOKEN( contentStatus ):
- m_aCustomPropertyName = "contentStatus";
+ m_aCustomPropertyName = "OOXMLCorePropertyContentStatus";
AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
break;
case COREPR_TOKEN( contentType ):
- m_aCustomPropertyName = "contentType";
+ m_aCustomPropertyName = "OOXMLCorePropertyContentType";
AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
break;
- case COREPR_TOKEN( identifier ):
- m_aCustomPropertyName = "identifier";
+ case DC_TOKEN( identifier ):
+ m_aCustomPropertyName = "OOXMLCorePropertyIdentifier";
AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
break;
case COREPR_TOKEN( version ):
- m_aCustomPropertyName = "version";
+ m_aCustomPropertyName = "OOXMLCorePropertyVersion";
AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
break;
@@ -537,47 +537,68 @@ void SAL_CALL OOXMLDocPropHandler::characters( const OUString& aChars )
case EXTPR_TOKEN( HyperlinksChanged ):
m_aCustomPropertyName = "HyperlinksChanged";
- AddCustomProperty( uno::makeAny( aChars.toBoolean() ) ); // the property has boolean type
+ // tdf#103987 Don't create custom property if the value is default
+ if ( aChars.toBoolean() )
+ AddCustomProperty( uno::makeAny( aChars.toBoolean() ) ); // the property has boolean type
break;
case EXTPR_TOKEN( LinksUpToDate ):
m_aCustomPropertyName = "LinksUpToDate";
- AddCustomProperty( uno::makeAny( aChars.toBoolean() ) ); // the property has boolean type
+ // tdf#103987 Don't create custom property if the value is default
+ if ( aChars.toBoolean() )
+ AddCustomProperty( uno::makeAny( aChars.toBoolean() ) ); // the property has boolean type
break;
case EXTPR_TOKEN( ScaleCrop ):
m_aCustomPropertyName = "ScaleCrop";
- AddCustomProperty( uno::makeAny( aChars.toBoolean() ) ); // the property has boolean type
+ // tdf#103987 Don't create custom property if the value is default
+ if ( aChars.toBoolean() )
+ AddCustomProperty( uno::makeAny( aChars.toBoolean() ) ); // the property has boolean type
break;
case EXTPR_TOKEN( SharedDoc ):
m_aCustomPropertyName = "ShareDoc";
- AddCustomProperty( uno::makeAny( aChars.toBoolean() ) ); // the property has boolean type
+ // tdf#103987 Don't create custom property if the value is default
+ if ( aChars.toBoolean() )
+ AddCustomProperty( uno::makeAny( aChars.toBoolean() ) ); // the property has boolean type
break;
case EXTPR_TOKEN( DocSecurity ):
m_aCustomPropertyName = "DocSecurity";
- AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
+ // tdf#103987 Don't create custom property if the value is default
+ // OOXTODO Instead of storing value, enable security
+ // 1 - password protected, 2 - recommended read-only
+ // 4 - enforced read-only, 8 - locked for annotation
+ if ( aChars.toInt32() != 0 )
+ AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
break;
case EXTPR_TOKEN( HiddenSlides ):
m_aCustomPropertyName = "HiddenSlides";
- AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
+ // tdf#103987 Don't create custom property if the value is default
+ if ( aChars.toInt32() != 0 )
+ AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
break;
case EXTPR_TOKEN( MMClips ):
m_aCustomPropertyName = "MMClips";
- AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
+ // tdf#103987 Don't create custom property if the value is default
+ if ( aChars.toInt32() != 0 )
+ AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
break;
case EXTPR_TOKEN( Notes ):
m_aCustomPropertyName = "Notes";
- AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
+ // tdf#103987 Don't create custom property if the value is default
+ if ( aChars.toInt32() != 0 )
+ AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
break;
case EXTPR_TOKEN( Slides ):
m_aCustomPropertyName = "Slides";
- AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
+ // tdf#103987 Don't create custom property if the value is default
+ if ( aChars.toInt32() != 0 )
+ AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
break;
case EXTPR_TOKEN( AppVersion ):