From 98af842308727765050a6e03cdb0b25b5694bd27 Mon Sep 17 00:00:00 2001 From: Ashod Nakashian Date: Tue, 6 Mar 2018 22:43:34 -0500 Subject: oox: preserve the ContentType of custom files Generic logic to preserve custom files with their correct ContentType. Standard default file extensions with respective ContentType preserved in [Content_Types].xml. Change-Id: I651ed691e9a4745cd2cb4b3c4d4c5fd7287b66c2 Reviewed-on: https://gerrit.libreoffice.org/50896 Reviewed-by: Jan Holesovsky Tested-by: Jan Holesovsky --- comphelper/source/xml/ofopxmlhelper.cxx | 32 +++++++++++++++++++++++++++ include/comphelper/ofopxmlhelper.hxx | 12 ++++++++++ oox/source/core/xmlfilterbase.cxx | 38 ++++++++++++++++++++++---------- package/source/zippackage/ZipPackage.cxx | 12 ++++++---- 4 files changed, 78 insertions(+), 16 deletions(-) diff --git a/comphelper/source/xml/ofopxmlhelper.cxx b/comphelper/source/xml/ofopxmlhelper.cxx index 6946e0e3bbd6..9bd5cad0fe8f 100644 --- a/comphelper/source/xml/ofopxmlhelper.cxx +++ b/comphelper/source/xml/ofopxmlhelper.cxx @@ -112,6 +112,38 @@ uno::Sequence< uno::Sequence< beans::StringPair > > ReadContentTypeSequence( return ReadSequence_Impl( xInStream, aStringID, CONTENTTYPE_FORMAT, rContext ); } +OUString GetContentTypeByName( + const css::uno::Sequence>& rContentTypes, + const OUString& rFilename) +{ + if (rContentTypes.getLength() < 2) + { + return OUString(); + } + + const uno::Sequence& rDefaults = rContentTypes[0]; + const uno::Sequence& rOverrides = rContentTypes[1]; + + // Find the extension and use it to get the type. + const sal_Int32 nDotOffset = rFilename.lastIndexOf('.'); + const OUString aExt = (nDotOffset >= 0 ? rFilename.copy(nDotOffset + 1) : rFilename); // Skip the dot. + + const std::vector aNames = { aExt, "/" + rFilename }; + for (const OUString& aName : aNames) + { + const auto it1 = std::find_if(rOverrides.begin(), rOverrides.end(), [&aName](const beans::StringPair& rPair) + { return rPair.First == aName; }); + if (it1 != rOverrides.end()) + return it1->Second; + + const auto it2 = std::find_if(rDefaults.begin(), rDefaults.end(), [&aName](const beans::StringPair& rPair) + { return rPair.First == aName; }); + if (it2 != rDefaults.end()) + return it2->Second; + } + + return OUString(); +} void WriteRelationsInfoSequence( const uno::Reference< io::XOutputStream >& xOutStream, diff --git a/include/comphelper/ofopxmlhelper.hxx b/include/comphelper/ofopxmlhelper.hxx index 3f03a39c5301..0c8183115206 100644 --- a/include/comphelper/ofopxmlhelper.hxx +++ b/include/comphelper/ofopxmlhelper.hxx @@ -56,6 +56,18 @@ namespace OFOPXMLHelper { const css::uno::Reference< css::uno::XComponentContext >& rContext ) throw( css::uno::Exception ); + // returns the ContentType for the given name, or empty when not found. + // rContentTypes is a sequence containing two entries of type sequence + // the first sequence describes "Default" elements, where each element is described + // by StringPair object ( First - Extension, Second - ContentType ) + // the second sequence describes "Override" elements, where each element is described + // by StringPair object ( First - PartName, Second - ContentType ) + // The "Override" sequence is searched first before falling back on "Default". + COMPHELPER_DLLPUBLIC + OUString + GetContentTypeByName(const css::uno::Sequence>& rContentTypes, + const OUString& rFilename); + // writes sequence of elements, where each element is described by sequence of tags, // where each tag is described by StringPair ( First - name, Second - value ) // the first tag of each element sequence must be "Id" diff --git a/oox/source/core/xmlfilterbase.cxx b/oox/source/core/xmlfilterbase.cxx index 00d23a377564..491d83a5770c 100644 --- a/oox/source/core/xmlfilterbase.cxx +++ b/oox/source/core/xmlfilterbase.cxx @@ -61,6 +61,7 @@ #include #include #include +#include #include #include @@ -961,13 +962,6 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference xRelations(xDocumentStorage, UNO_QUERY); if (xRelations.is()) { - // These are all the custom types we recognize and can preserve. - static const std::set sCustomTypes = { - "http://schemas.dell.com/ddp/2016/relationships/xenFile", - "http://schemas.dell.com/ddp/2016/relationships/hmacFile", - "http://schemas.dell.com/ddp/2016/relationships/metadataFile" - }; - uno::Sequence> aSeqs = xRelations->getAllRelationships(); std::vector aCustomFragments; @@ -987,7 +981,8 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference> aCustomXmlDomPropsList; //FIXME: Ideally, we should get these the relations, but it seems that is not consistently set. // In some cases it's stored in the workbook relationships, which is unexpected. So we discover them directly. - for (int i = 1; i < 100; ++i) + for (int i = 1; ; ++i) { Reference xCustDoc = importFragment("customXml/item" + OUString::number(i) + ".xml"); Reference xCustDocProps = importFragment("customXml/itemProps" + OUString::number(i) + ".xml"); @@ -1026,6 +1021,14 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference> aContentTypeInfo; + uno::Reference xInputStream = openInputStream("[Content_Types].xml"); + if (xInputStream.is()) + aContentTypeInfo = comphelper::OFOPXMLHelper::ReadContentTypeSequence(xInputStream, getComponentContext()); + + aGrabBagProperties["OOXContentTypes"] <<= aContentTypeInfo; + Reference xModel(getModel(), UNO_QUERY); oox::core::XmlFilterBase::putPropertiesToDocumentGrabBag(xModel, aGrabBagProperties); } @@ -1046,6 +1049,7 @@ void XmlFilterBase::exportCustomFragments() uno::Sequence customFragments; uno::Sequence customFragmentTypes; uno::Sequence customFragmentTargets; + uno::Sequence> aContentTypes; uno::Sequence propList; xPropSet->getPropertyValue(aName) >>= propList; @@ -1072,6 +1076,10 @@ void XmlFilterBase::exportCustomFragments() { propList[nProp].Value >>= customFragmentTargets; } + else if (propName == "OOXContentTypes") + { + propList[nProp].Value >>= aContentTypes; + } } // Expect customXmlDomPropslist.getLength() == customXmlDomlist.getLength(). @@ -1111,10 +1119,16 @@ void XmlFilterBase::exportCustomFragments() for (sal_Int32 j = 0; j < customFragments.getLength(); j++) { addRelation(customFragmentTypes[j], customFragmentTargets[j]); - Reference xOutStream = openOutputStream(customFragmentTargets[j]); + const OUString aFilename = customFragmentTargets[j]; + Reference xOutStream = openOutputStream(aFilename); xOutStream->writeBytes(customFragments[j]); - // BinaryXInputStream aInStrm(openOutputStream(customFragmentTargets[j]), true); - // aInStrm.copyToStream(xOutputStream); + uno::Reference xProps(xOutStream, uno::UNO_QUERY); + if (xProps.is()) + { + const OUString aType = comphelper::OFOPXMLHelper::GetContentTypeByName(aContentTypes, aFilename); + const OUString aContentType = (aType.getLength() ? aType : OUString("application/octet-stream")); + xProps->setPropertyValue("MediaType", uno::makeAny(aContentType)); + } } } diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx index b59cca3ac22e..11d0890d67d6 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -1054,11 +1054,16 @@ void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno: // Convert vector into a uno::Sequence // TODO/LATER: use Default entries in future - uno::Sequence< beans::StringPair > aDefaultsSequence(aManList.size()); - // Add at least the application/xml default entry. + uno::Sequence< beans::StringPair > aDefaultsSequence(4); + // Add at least the standard default entries. aDefaultsSequence[0].First = "xml"; aDefaultsSequence[0].Second= "application/xml"; - sal_Int32 nDefSeqLength = 1; + aDefaultsSequence[1].First = "rels"; + aDefaultsSequence[1].Second= "application/vnd.openxmlformats-package.relationships+xml"; + aDefaultsSequence[2].First = "png"; + aDefaultsSequence[2].Second= "image/png"; + aDefaultsSequence[3].First = "jpeg"; + aDefaultsSequence[3].Second= "image/jpeg"; uno::Sequence< beans::StringPair > aOverridesSequence(aManList.size()); sal_Int32 nOverSeqLength = 0; @@ -1083,7 +1088,6 @@ void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno: } } aOverridesSequence.realloc(nOverSeqLength); - aDefaultsSequence.realloc(nDefSeqLength); ::comphelper::OFOPXMLHelper::WriteContentSequence( xConTypeOutStream, aDefaultsSequence, aOverridesSequence, m_xContext ); -- cgit