summaryrefslogtreecommitdiffstats
path: root/oox/source/docprop
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/docprop')
-rw-r--r--oox/source/docprop/docprophandler.cxx719
-rw-r--r--oox/source/docprop/docprophandler.hxx90
-rw-r--r--oox/source/docprop/ooxmldocpropimport.cxx171
-rw-r--r--oox/source/docprop/ooxmldocpropimport.hxx59
4 files changed, 1039 insertions, 0 deletions
diff --git a/oox/source/docprop/docprophandler.cxx b/oox/source/docprop/docprophandler.cxx
new file mode 100644
index 000000000..07f9b4c0d
--- /dev/null
+++ b/oox/source/docprop/docprophandler.cxx
@@ -0,0 +1,719 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "docprophandler.hxx"
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyExistException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/xml/sax/SAXException.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <o3tl/safeint.hxx>
+#include <osl/time.h>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+#include <vector>
+#include <boost/algorithm/string.hpp>
+
+#include <oox/helper/attributelist.hxx>
+
+using namespace ::com::sun::star;
+
+namespace oox::docprop {
+
+OOXMLDocPropHandler::OOXMLDocPropHandler( const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< document::XDocumentProperties >& rDocProp )
+ : m_xDocProp( rDocProp )
+ , m_nState( 0 )
+ , m_nBlock( 0 )
+ , m_nType( 0 )
+ , m_nInBlock( 0 )
+ , m_CustomStringPropertyState(NONE)
+{
+ if ( !xContext.is() || !rDocProp.is() )
+ throw uno::RuntimeException();
+}
+
+OOXMLDocPropHandler::~OOXMLDocPropHandler()
+{
+}
+
+void OOXMLDocPropHandler::InitNew()
+{
+ m_nState = 0;
+ m_nBlock = 0;
+ m_aCustomPropertyName.clear();
+ m_nType = 0;
+ m_nInBlock = 0;
+ m_CustomStringPropertyState = NONE;
+}
+
+void OOXMLDocPropHandler::AddCustomProperty( const uno::Any& aAny )
+{
+ if ( m_aCustomPropertyName.isEmpty() )
+ return;
+
+ const uno::Reference< beans::XPropertyContainer > xUserProps =
+ m_xDocProp->getUserDefinedProperties();
+ if ( !xUserProps.is() )
+ throw uno::RuntimeException();
+
+ try
+ {
+ xUserProps->addProperty( m_aCustomPropertyName,
+ beans::PropertyAttribute::REMOVABLE, aAny );
+ }
+ catch( beans::PropertyExistException& )
+ {
+ // conflicts with core and extended properties are possible
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( "Can not add custom property!" );
+ }
+}
+
+util::DateTime OOXMLDocPropHandler::GetDateTimeFromW3CDTF( const OUString& aChars )
+{
+ oslDateTime aOslDTime = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ const sal_Int32 nLen = aChars.getLength();
+ if ( nLen >= 4 )
+ {
+ aOslDTime.Year = static_cast<sal_Int16>(aChars.copy( 0, 4 ).toInt32());
+
+ if ( nLen >= 7 && aChars[4] == '-' )
+ {
+ aOslDTime.Month = static_cast<sal_uInt16>(aChars.copy( 5, 2 ).toInt32());
+
+ if ( nLen >= 10 && aChars[7] == '-' )
+ {
+ aOslDTime.Day = static_cast<sal_uInt16>(aChars.copy( 8, 2 ).toInt32());
+
+ if ( nLen >= 16 && aChars[10] == 'T' && aChars[13] == ':' )
+ {
+ aOslDTime.Hours = static_cast<sal_uInt16>(aChars.copy( 11, 2 ).toInt32());
+ aOslDTime.Minutes = static_cast<sal_uInt16>(aChars.copy( 14, 2 ).toInt32());
+
+ sal_Int32 nOptTime = 0;
+ if ( nLen >= 19 && aChars[16] == ':' )
+ {
+ aOslDTime.Seconds = static_cast<sal_uInt16>(aChars.copy( 17, 2 ).toInt32());
+ nOptTime += 3;
+ if ( nLen >= 20 && aChars[19] == '.' )
+ {
+ nOptTime += 1;
+ sal_Int32 digitPos = 20;
+ while (nLen > digitPos && digitPos < 29)
+ {
+ sal_Unicode c = aChars[digitPos];
+ if ( c < '0' || c > '9')
+ break;
+ aOslDTime.NanoSeconds *= 10;
+ aOslDTime.NanoSeconds += c - '0';
+ ++digitPos;
+ }
+ if ( digitPos < 29 )
+ {
+ // read less digits than 9
+ // add correct exponent of 10
+ nOptTime += digitPos - 20;
+ for(; digitPos<29; ++digitPos)
+ {
+ aOslDTime.NanoSeconds *= 10;
+ }
+ }
+ else
+ {
+ //skip digits with more precision than we can handle
+ while(nLen > digitPos)
+ {
+ sal_Unicode c = aChars[digitPos];
+ if ( c < '0' || c > '9')
+ break;
+ ++digitPos;
+ }
+ nOptTime += digitPos - 20;
+ }
+ }
+ }
+
+ sal_Int32 nModif = 0;
+ if ( nLen >= 16 + nOptTime + 6 )
+ {
+ if ( ( aChars[16 + nOptTime] == '+' || aChars[16 + nOptTime] == '-' )
+ && aChars[16 + nOptTime + 3] == ':' )
+ {
+ nModif = aChars.copy( 16 + nOptTime + 1, 2 ).toInt32() * 3600;
+ nModif += aChars.copy( 16 + nOptTime + 4, 2 ).toInt32() * 60;
+ if ( aChars[16 + nOptTime] == '-' )
+ nModif *= -1;
+ }
+ }
+
+ if ( nModif )
+ {
+ // convert to UTC time
+ TimeValue aTmp;
+ if ( osl_getTimeValueFromDateTime( &aOslDTime, &aTmp ) )
+ {
+ aTmp.Seconds -= nModif;
+ osl_getDateTimeFromTimeValue( &aTmp, &aOslDTime );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return util::DateTime( aOslDTime.NanoSeconds, aOslDTime.Seconds,
+ aOslDTime.Minutes, aOslDTime.Hours,
+ aOslDTime.Day, aOslDTime.Month, aOslDTime.Year, false);
+}
+
+uno::Sequence< OUString > OOXMLDocPropHandler::GetKeywordsSet( const OUString& aChars )
+{
+ if ( !aChars.isEmpty() )
+ {
+ std::string aUtf8Chars = OUStringToOString( aChars, RTL_TEXTENCODING_UTF8 ).getStr();
+ std::vector<std::string> aUtf8Result;
+ boost::split( aUtf8Result, aUtf8Chars, boost::is_any_of(" ,;:\t"), boost::token_compress_on );
+
+ if (!aUtf8Result.empty())
+ {
+ uno::Sequence< OUString > aResult( aUtf8Result.size() );
+ OUString* pResultValues = aResult.getArray();
+ for (auto const& elem : aUtf8Result)
+ {
+ *pResultValues = OUString( elem.c_str(), static_cast< sal_Int32 >( elem.size() ),RTL_TEXTENCODING_UTF8 );
+ ++pResultValues;
+ }
+
+ return aResult;
+ }
+ }
+ return uno::Sequence< OUString >();
+}
+
+void OOXMLDocPropHandler::UpdateDocStatistic( const OUString& aChars )
+{
+ uno::Sequence< beans::NamedValue > aSet = m_xDocProp->getDocumentStatistics();
+ OUString aName;
+
+ switch( m_nBlock )
+ {
+ case EXTPR_TOKEN( Characters ):
+ aName = "NonWhitespaceCharacterCount";
+ break;
+
+ case EXTPR_TOKEN( CharactersWithSpaces ):
+ aName = "CharacterCount";
+ break;
+
+ case EXTPR_TOKEN( Pages ):
+ aName = "PageCount";
+ break;
+
+ case EXTPR_TOKEN( Words ):
+ aName = "WordCount";
+ break;
+
+ case EXTPR_TOKEN( Paragraphs ):
+ aName = "ParagraphCount";
+ break;
+
+ default:
+ OSL_FAIL( "Unexpected statistic!" );
+ break;
+ }
+
+ if ( aName.isEmpty() )
+ return;
+
+ sal_Int32 nInd = 0;
+ for ( auto pProp = aSet.getConstArray(); nInd < aSet.getLength(); ++nInd )
+ if ( pProp[nInd].Name == aName )
+ break;
+
+ if (nInd == aSet.getLength())
+ aSet.realloc( nInd + 1 );
+
+ beans::NamedValue aProp;
+ aProp.Name = aName;
+ aProp.Value <<= aChars.toInt32();
+
+ aSet[nInd] = aProp;
+
+ m_xDocProp->setDocumentStatistics( aSet );
+}
+
+// com.sun.star.xml.sax.XFastDocumentHandler
+
+void SAL_CALL OOXMLDocPropHandler::startDocument()
+{
+}
+
+void SAL_CALL OOXMLDocPropHandler::endDocument()
+{
+ InitNew();
+}
+
+void OOXMLDocPropHandler::processingInstruction( const OUString& /*rTarget*/, const OUString& /*rData*/ )
+{
+}
+
+void SAL_CALL OOXMLDocPropHandler::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& )
+{
+}
+
+// com.sun.star.xml.sax.XFastContextHandler
+
+void SAL_CALL OOXMLDocPropHandler::startFastElement( ::sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttribs )
+{
+ if ( !m_nInBlock && !m_nState )
+ {
+ if ( nElement == COREPR_TOKEN( coreProperties )
+ || nElement == EXTPR_TOKEN( Properties )
+ || nElement == CUSTPR_TOKEN( Properties ) )
+ {
+ m_nState = nElement;
+ }
+ else
+ {
+ OSL_FAIL( "Unexpected file format!" );
+ }
+ }
+ else if ( m_nState && m_nInBlock == 1 ) // that tag should contain the property name
+ {
+ // Currently the attributes are ignored for the core properties since the only
+ // known attribute is xsi:type that can only be used with dcterms:created and
+ // dcterms:modified, and this element is allowed currently to have only one value dcterms:W3CDTF
+ m_nBlock = nElement;
+
+ if ( xAttribs.is() && xAttribs->hasAttribute( XML_name ) )
+ m_aCustomPropertyName = xAttribs->getValue( XML_name );
+ }
+ else if ( m_nState && m_nInBlock == 2 && getNamespace( nElement ) == NMSP_officeDocPropsVT )
+ {
+ m_nType = nElement;
+ }
+ // variant tags in vector
+ else if ( m_nState && m_nInBlock == 3 && getNamespace( nElement ) == NMSP_officeDocPropsVT )
+ {
+ m_nType = nElement;
+ }
+ // lpstr or i4 tags in vector
+ else if ( m_nState && m_nInBlock == 4 && getNamespace( nElement ) == NMSP_officeDocPropsVT )
+ {
+ m_nType = nElement;
+ }
+ else
+ {
+ SAL_WARN("oox", "OOXMLDocPropHandler::startFastElement: unknown element " << getBaseToken(nElement) << " m_nState=" << m_nState << " m_nInBlock=" << m_nInBlock);
+ }
+
+ if ( m_nInBlock == SAL_MAX_INT32 )
+ throw uno::RuntimeException();
+
+ m_nInBlock++;
+}
+
+void SAL_CALL OOXMLDocPropHandler::startUnknownElement( const OUString& aNamespace, const OUString& aName, const uno::Reference< xml::sax::XFastAttributeList >& )
+{
+ SAL_WARN("oox", "Unknown element " << aNamespace << ":" << aName);
+
+ if ( m_nInBlock == SAL_MAX_INT32 )
+ throw uno::RuntimeException();
+
+ m_nInBlock++;
+}
+
+void SAL_CALL OOXMLDocPropHandler::endFastElement( ::sal_Int32 )
+{
+ if ( !m_nInBlock )
+ return;
+
+ m_nInBlock--;
+
+ if ( !m_nInBlock )
+ m_nState = 0;
+ else if ( m_nInBlock == 1 )
+ {
+ m_nBlock = 0;
+ m_aCustomPropertyName.clear();
+ }
+ else if ( m_nInBlock == 2 )
+ {
+ if ( m_nState == CUSTPR_TOKEN(Properties)
+ && m_nBlock == CUSTPR_TOKEN(property))
+ {
+ switch (m_nType)
+ {
+ case VT_TOKEN(bstr):
+ case VT_TOKEN(lpstr):
+ case VT_TOKEN(lpwstr):
+ if (!m_aCustomPropertyName.isEmpty() &&
+ INSERTED != m_CustomStringPropertyState)
+ {
+ // the property has string type, so it is valid
+ // even with an empty value - characters() has
+ // not been called in that case
+ AddCustomProperty(uno::makeAny(OUString()));
+ }
+ break;
+ }
+ }
+ m_CustomStringPropertyState = NONE;
+ m_nType = 0;
+ }
+}
+
+void SAL_CALL OOXMLDocPropHandler::endUnknownElement( const OUString&, const OUString& )
+{
+ if ( m_nInBlock )
+ m_nInBlock--;
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL OOXMLDocPropHandler::createFastChildContext( ::sal_Int32, const uno::Reference< xml::sax::XFastAttributeList >& )
+{
+ // Should the arguments be parsed?
+ return uno::Reference< xml::sax::XFastContextHandler >( static_cast< xml::sax::XFastContextHandler* >( this ) );
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL OOXMLDocPropHandler::createUnknownChildContext( const OUString&, const OUString&, const uno::Reference< xml::sax::XFastAttributeList >& )
+{
+ return uno::Reference< xml::sax::XFastContextHandler >( static_cast< xml::sax::XFastContextHandler* >( this ) );
+}
+
+void SAL_CALL OOXMLDocPropHandler::characters( const OUString& aChars )
+{
+ try
+ {
+ if ( (m_nInBlock == 2) || ((m_nInBlock == 3) && m_nType) )
+ {
+ if ( m_nState == COREPR_TOKEN( coreProperties ) )
+ {
+ switch( m_nBlock )
+ {
+ case COREPR_TOKEN( category ):
+ m_aCustomPropertyName = "OOXMLCorePropertyCategory";
+ AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
+ break;
+
+ case COREPR_TOKEN( contentStatus ):
+ m_aCustomPropertyName = "OOXMLCorePropertyContentStatus";
+ AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
+ break;
+
+ case COREPR_TOKEN( contentType ):
+ m_aCustomPropertyName = "OOXMLCorePropertyContentType";
+ AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
+ break;
+
+ case DC_TOKEN( identifier ):
+ m_aCustomPropertyName = "OOXMLCorePropertyIdentifier";
+ AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
+ break;
+
+ case COREPR_TOKEN( version ):
+ m_aCustomPropertyName = "OOXMLCorePropertyVersion";
+ AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
+ break;
+
+ case DCT_TOKEN( created ):
+ if ( aChars.getLength() >= 4 )
+ m_xDocProp->setCreationDate( GetDateTimeFromW3CDTF( aChars ) );
+ break;
+
+ case DC_TOKEN( creator ):
+ m_xDocProp->setAuthor( aChars );
+ break;
+
+ case DC_TOKEN( description ):
+ m_xDocProp->setDescription( aChars );
+ break;
+
+ case COREPR_TOKEN( keywords ):
+ m_xDocProp->setKeywords( GetKeywordsSet( aChars ) );
+ break;
+
+ case DC_TOKEN( language ):
+ if ( aChars.getLength() >= 2 )
+ m_xDocProp->setLanguage( LanguageTag::convertToLocale( aChars) );
+ break;
+
+ case COREPR_TOKEN( lastModifiedBy ):
+ m_xDocProp->setModifiedBy( aChars );
+ break;
+
+ case COREPR_TOKEN( lastPrinted ):
+ if ( aChars.getLength() >= 4 )
+ m_xDocProp->setPrintDate( GetDateTimeFromW3CDTF( aChars ) );
+ break;
+
+ case DCT_TOKEN( modified ):
+ if ( aChars.getLength() >= 4 )
+ m_xDocProp->setModificationDate( GetDateTimeFromW3CDTF( aChars ) );
+ break;
+
+ case COREPR_TOKEN( revision ):
+ try
+ {
+ m_xDocProp->setEditingCycles(
+ static_cast<sal_Int16>(aChars.toInt32()) );
+ }
+ catch (lang::IllegalArgumentException &)
+ {
+ // ignore
+ }
+ break;
+
+ case DC_TOKEN( subject ):
+ m_xDocProp->setSubject( m_xDocProp->getSubject() + aChars );
+ break;
+
+ case DC_TOKEN( title ):
+ m_xDocProp->setTitle( m_xDocProp->getTitle() + aChars );
+ break;
+
+ default:
+ OSL_FAIL( "Unexpected core property!" );
+ }
+ }
+ else if ( m_nState == EXTPR_TOKEN( Properties ) )
+ {
+ switch( m_nBlock )
+ {
+ case EXTPR_TOKEN( Application ):
+ m_xDocProp->setGenerator( aChars );
+ break;
+
+ case EXTPR_TOKEN( Template ):
+ m_xDocProp->setTemplateName( aChars );
+ break;
+
+ case EXTPR_TOKEN( TotalTime ):
+ {
+ sal_Int32 nDuration;
+ if (!o3tl::checked_multiply<sal_Int32>(aChars.toInt32(), 60, nDuration))
+ {
+ try
+ {
+ // The TotalTime is in mins as per ECMA specification.
+ m_xDocProp->setEditingDuration(nDuration);
+ }
+ catch (const lang::IllegalArgumentException&)
+ {
+ // ignore
+ }
+ }
+ break;
+ }
+ case EXTPR_TOKEN( Characters ):
+ case EXTPR_TOKEN( CharactersWithSpaces ):
+ case EXTPR_TOKEN( Pages ):
+ case EXTPR_TOKEN( Words ):
+ case EXTPR_TOKEN( Paragraphs ):
+ UpdateDocStatistic( aChars );
+ break;
+
+ case EXTPR_TOKEN( HyperlinksChanged ):
+ m_aCustomPropertyName = "HyperlinksChanged";
+ // 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";
+ // 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";
+ // 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";
+ // 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";
+ // 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";
+ // 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";
+ // 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";
+ // 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";
+ // 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 ):
+ m_aCustomPropertyName = "AppVersion";
+ AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
+ break;
+
+ case EXTPR_TOKEN( Company ):
+ m_aCustomPropertyName = "Company";
+ AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
+ break;
+
+ case EXTPR_TOKEN( HyperlinkBase ):
+ m_aCustomPropertyName = "HyperlinkBase";
+ AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
+ break;
+
+ case EXTPR_TOKEN( Manager ):
+ m_aCustomPropertyName = "Manager";
+ AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
+ break;
+
+ case EXTPR_TOKEN( PresentationFormat ):
+ m_aCustomPropertyName = "PresentationFormat";
+ AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
+ break;
+
+ case EXTPR_TOKEN( Lines ):
+ case EXTPR_TOKEN( DigSig ):
+ case EXTPR_TOKEN( HeadingPairs ):
+ case EXTPR_TOKEN( HLinks ):
+ case EXTPR_TOKEN( TitlesOfParts ):
+ // ignored during the import currently
+ break;
+
+ default:
+ OSL_FAIL( "Unexpected extended property!" );
+ }
+ }
+ else if ( m_nState == CUSTPR_TOKEN( Properties ) )
+ {
+ if ( m_nBlock == CUSTPR_TOKEN( property ) )
+ {
+ // this is a custom property
+ switch( m_nType )
+ {
+ case VT_TOKEN( bool ):
+ AddCustomProperty( uno::makeAny( aChars.toBoolean() ) );
+ break;
+
+ case VT_TOKEN( bstr ):
+ case VT_TOKEN( lpstr ):
+ case VT_TOKEN( lpwstr ):
+ // the property has string type
+ AddCustomProperty( uno::makeAny( AttributeConversion::decodeXString( aChars ) ) );
+ m_CustomStringPropertyState = INSERTED;
+ break;
+
+ case VT_TOKEN( date ):
+ case VT_TOKEN( filetime ):
+ AddCustomProperty( uno::makeAny( GetDateTimeFromW3CDTF( aChars ) ) );
+ break;
+
+ case VT_TOKEN( i1 ):
+ case VT_TOKEN( i2 ):
+ AddCustomProperty( uno::makeAny( static_cast<sal_Int16>(aChars.toInt32()) ) );
+ break;
+
+ case VT_TOKEN( i4 ):
+ case VT_TOKEN( int ):
+ AddCustomProperty( uno::makeAny( aChars.toInt32() ) );
+ break;
+
+ case VT_TOKEN( i8 ):
+ AddCustomProperty( uno::makeAny( aChars.toInt64() ) );
+ break;
+
+ case VT_TOKEN( r4 ):
+ AddCustomProperty( uno::makeAny( aChars.toFloat() ) );
+ break;
+
+ case VT_TOKEN( r8 ):
+ AddCustomProperty( uno::makeAny( aChars.toDouble() ) );
+ break;
+
+ default:
+ // all the other types are ignored;
+ break;
+ }
+ }
+ else
+ {
+ OSL_FAIL( "Unexpected tag in custom property!" );
+ }
+ }
+ }
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( xml::sax::SAXException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw xml::sax::SAXException(
+ "Error while setting document property!",
+ uno::Reference< uno::XInterface >(),
+ anyEx );
+ }
+}
+
+} // namespace oox::docprop
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/docprop/docprophandler.hxx b/oox/source/docprop/docprophandler.hxx
new file mode 100644
index 000000000..d3baa3fd6
--- /dev/null
+++ b/oox/source/docprop/docprophandler.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_OOX_SOURCE_DOCPROP_DOCPROPHANDLER_HXX
+#define INCLUDED_OOX_SOURCE_DOCPROP_DOCPROPHANDLER_HXX
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/xml/sax/XFastDocumentHandler.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <oox/token/namespaces.hxx>
+
+namespace oox {
+namespace docprop {
+
+#define COREPR_TOKEN( token ) (::oox::NMSP_packageMetaCorePr | XML_##token)
+#define CUSTPR_TOKEN( token ) (::oox::NMSP_officeCustomPr | XML_##token)
+#define EXTPR_TOKEN( token ) (::oox::NMSP_officeExtPr | XML_##token)
+#define VT_TOKEN( token ) (::oox::NMSP_officeDocPropsVT | XML_##token)
+#define DC_TOKEN( token ) (::oox::NMSP_dc | XML_##token)
+#define DCT_TOKEN( token ) (::oox::NMSP_dcTerms | XML_##token)
+
+class OOXMLDocPropHandler : public ::cppu::WeakImplHelper< css::xml::sax::XFastDocumentHandler >
+{
+ css::uno::Reference< css::document::XDocumentProperties > m_xDocProp;
+
+ sal_Int32 m_nState;
+ sal_Int32 m_nBlock;
+ sal_Int32 m_nType;
+
+ sal_Int32 m_nInBlock;
+
+ enum { NONE, INSERTED } m_CustomStringPropertyState;
+ OUString m_aCustomPropertyName;
+
+public:
+ explicit OOXMLDocPropHandler( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::document::XDocumentProperties >& rDocProp );
+
+ virtual ~OOXMLDocPropHandler() override;
+
+ void InitNew();
+ void AddCustomProperty( const css::uno::Any& aAny );
+
+ static css::util::DateTime GetDateTimeFromW3CDTF( const OUString& aChars );
+ static css::uno::Sequence< OUString > GetKeywordsSet( const OUString& aChars );
+ void UpdateDocStatistic( const OUString& aChars );
+
+ // com.sun.star.xml.sax.XFastDocumentHandler
+
+ virtual void SAL_CALL startDocument() override;
+ virtual void SAL_CALL endDocument() override;
+ virtual void SAL_CALL processingInstruction( const OUString& rTarget, const OUString& rData ) override;
+ virtual void SAL_CALL setDocumentLocator( const css::uno::Reference< css::xml::sax::XLocator >& rxLocator ) override;
+
+ // com.sun.star.xml.sax.XFastContextHandler
+
+ virtual void SAL_CALL startFastElement( ::sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override;
+ virtual void SAL_CALL startUnknownElement( const OUString& Namespace, const OUString& Name, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override;
+ virtual void SAL_CALL endFastElement( ::sal_Int32 Element ) override;
+ virtual void SAL_CALL endUnknownElement( const OUString& Namespace, const OUString& Name ) override;
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override;
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext( const OUString& Namespace, const OUString& Name, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override;
+ virtual void SAL_CALL characters( const OUString& aChars ) override;
+
+};
+
+} // namespace core
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/docprop/ooxmldocpropimport.cxx b/oox/source/docprop/ooxmldocpropimport.cxx
new file mode 100644
index 000000000..621173b6b
--- /dev/null
+++ b/oox/source/docprop/ooxmldocpropimport.cxx
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ooxmldocpropimport.hxx"
+
+#include <vector>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
+#include <com/sun/star/embed/XRelationshipAccess.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <oox/core/fastparser.hxx>
+#include <oox/core/relations.hxx>
+#include <oox/helper/containerhelper.hxx>
+#include "docprophandler.hxx"
+
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace ::com::sun::star;
+
+namespace oox::docprop {
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::xml::sax;
+
+namespace {
+
+/// @throws RuntimeException
+/// @throws css::io::IOException
+Sequence< InputSource > lclGetRelatedStreams( const Reference< XStorage >& rxStorage, const OUString& rStreamType )
+{
+ Reference< XRelationshipAccess > xRelation( rxStorage, UNO_QUERY_THROW );
+ Reference< XHierarchicalStorageAccess > xHierarchy( rxStorage, UNO_QUERY_THROW );
+
+ const Sequence< Sequence< StringPair > > aPropsInfo = xRelation->getRelationshipsByType( rStreamType );
+
+ ::std::vector< InputSource > aResult;
+
+ for( const Sequence< StringPair >& rEntries : aPropsInfo )
+ {
+ auto pEntry = std::find_if(rEntries.begin(), rEntries.end(),
+ [](const StringPair& rEntry) { return rEntry.First == "Target"; });
+ if (pEntry != rEntries.end())
+ {
+ // The stream path is always a relative one, ignore the leading "/" if it's there.
+ OUString aStreamPath = pEntry->Second;
+ if (aStreamPath.startsWith("/"))
+ aStreamPath = aStreamPath.copy(1);
+
+ Reference< XExtendedStorageStream > xExtStream(
+ xHierarchy->openStreamElementByHierarchicalName( aStreamPath, ElementModes::READ ), UNO_SET_THROW );
+ Reference< XInputStream > xInStream = xExtStream->getInputStream();
+ if( xInStream.is() )
+ {
+ aResult.emplace_back();
+ aResult.back().sSystemId = pEntry->Second;
+ aResult.back().aInputStream = xExtStream->getInputStream();
+ }
+ }
+ }
+
+ return ContainerHelper::vectorToSequence( aResult );
+}
+
+} // namespace
+
+DocumentPropertiesImport::DocumentPropertiesImport( const Reference< XComponentContext >& rxContext ) :
+ mxContext( rxContext )
+{
+}
+
+// XServiceInfo
+OUString SAL_CALL DocumentPropertiesImport::getImplementationName()
+{
+ return "com.sun.star.comp.oox.docprop.DocumentPropertiesImporter";
+}
+
+sal_Bool SAL_CALL DocumentPropertiesImport::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > SAL_CALL DocumentPropertiesImport::getSupportedServiceNames()
+{
+ Sequence<OUString> aServices { "com.sun.star.document.OOXMLDocumentPropertiesImporter" };
+ return aServices;
+}
+
+// XOOXMLDocumentPropertiesImporter
+void SAL_CALL DocumentPropertiesImport::importProperties(
+ const Reference< XStorage >& rxSource, const Reference< XDocumentProperties >& rxDocumentProperties )
+{
+ if( !mxContext.is() )
+ throw RuntimeException();
+
+ if( !rxSource.is() || !rxDocumentProperties.is() )
+ throw IllegalArgumentException();
+
+ Sequence< InputSource > aCoreStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE( "metadata/core-properties" ) );
+ // OOXML strict
+ if( !aCoreStreams.hasElements() )
+ aCoreStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE_STRICT( "metadata/core-properties" ) );
+ // MS Office seems to have a bug, so we have to do similar handling
+ if( !aCoreStreams.hasElements() )
+ aCoreStreams = lclGetRelatedStreams( rxSource, "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" );
+
+ Sequence< InputSource > aExtStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE( "extended-properties" ) );
+ // OOXML strict
+ if( !aExtStreams.hasElements() )
+ aExtStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE_STRICT( "extended-properties" ) );
+ Sequence< InputSource > aCustomStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE( "custom-properties" ) );
+ // OOXML strict
+ if( !aCustomStreams.hasElements() )
+ aCustomStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE_STRICT( "custom-properties" ) );
+
+ if( !(aCoreStreams.hasElements() || aExtStreams.hasElements() || aCustomStreams.hasElements()) )
+ return;
+
+ if( aCoreStreams.getLength() > 1 )
+ throw IOException( "Unexpected core properties stream!" );
+
+ ::oox::core::FastParser aParser;
+ aParser.registerNamespace( NMSP_packageMetaCorePr );
+ aParser.registerNamespace( NMSP_dc );
+ aParser.registerNamespace( NMSP_dcTerms );
+ aParser.registerNamespace( NMSP_officeExtPr );
+ aParser.registerNamespace( NMSP_officeCustomPr );
+ aParser.registerNamespace( NMSP_officeDocPropsVT );
+ aParser.setDocumentHandler( new OOXMLDocPropHandler( mxContext, rxDocumentProperties ) );
+
+ if( aCoreStreams.hasElements() )
+ aParser.parseStream( aCoreStreams[ 0 ], true );
+ for( const auto& rExtStream : std::as_const(aExtStreams) )
+ aParser.parseStream( rExtStream, true );
+ for( const auto& rCustomStream : std::as_const(aCustomStreams) )
+ aParser.parseStream( rCustomStream, true );
+}
+
+} // namespace oox::docprop
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_comp_oox_docprop_DocumentPropertiesImporter_get_implementation(
+ uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new oox::docprop::DocumentPropertiesImport(pCtx));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/docprop/ooxmldocpropimport.hxx b/oox/source/docprop/ooxmldocpropimport.hxx
new file mode 100644
index 000000000..cc4301de2
--- /dev/null
+++ b/oox/source/docprop/ooxmldocpropimport.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_OOX_SOURCE_DOCPROP_OOXMLDOCPROPIMPORT_HXX
+#define INCLUDED_OOX_SOURCE_DOCPROP_OOXMLDOCPROPIMPORT_HXX
+
+#include <com/sun/star/document/XOOXMLDocumentPropertiesImporter.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace oox {
+namespace docprop {
+
+class DocumentPropertiesImport :
+ public ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo,
+ css::document::XOOXMLDocumentPropertiesImporter >
+{
+public:
+ explicit DocumentPropertiesImport(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XOOXMLDocumentPropertiesImporter
+ virtual void SAL_CALL importProperties(
+ const css::uno::Reference< css::embed::XStorage >& rxSource,
+ const css::uno::Reference< css::document::XDocumentProperties >& rxDocumentProperties ) override;
+
+private:
+ css::uno::Reference< css::uno::XComponentContext > mxContext;
+};
+
+} // namespace docprop
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */