[Libreoffice-commits] core.git: comphelper/source include/comphelper oox/source package/source

Ashod Nakashian ashod.nakashian at collabora.co.uk
Thu Mar 8 11:40:47 UTC 2018


 comphelper/source/xml/ofopxmlhelper.cxx  |   32 ++++++++++++++++++++++++++
 include/comphelper/ofopxmlhelper.hxx     |   12 +++++++++
 oox/source/core/xmlfilterbase.cxx        |   38 +++++++++++++++++++++----------
 package/source/zippackage/ZipPackage.cxx |   10 ++++++--
 4 files changed, 78 insertions(+), 14 deletions(-)

New commits:
commit 8f79f22a8d4b1c2d209c55cd618c24428960088f
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Tue Mar 6 22:43:34 2018 -0500

    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/50856
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>

diff --git a/comphelper/source/xml/ofopxmlhelper.cxx b/comphelper/source/xml/ofopxmlhelper.cxx
index d3ce7b0dc65d..bfb3dbdd0fa6 100644
--- a/comphelper/source/xml/ofopxmlhelper.cxx
+++ b/comphelper/source/xml/ofopxmlhelper.cxx
@@ -110,6 +110,38 @@ uno::Sequence< uno::Sequence< beans::StringPair > > ReadContentTypeSequence(
     return ReadSequence_Impl( xInStream, aStringID, CONTENTTYPE_FORMAT, rContext );
 }
 
+OUString GetContentTypeByName(
+                const css::uno::Sequence<css::uno::Sequence<css::beans::StringPair>>& rContentTypes,
+                const OUString& rFilename)
+{
+    if (rContentTypes.getLength() < 2)
+    {
+        return OUString();
+    }
+
+    const uno::Sequence<beans::StringPair>& rDefaults = rContentTypes[0];
+    const uno::Sequence<beans::StringPair>& 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<OUString> 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 c0215a0d21d3..8c3b62be3956 100644
--- a/include/comphelper/ofopxmlhelper.hxx
+++ b/include/comphelper/ofopxmlhelper.hxx
@@ -56,6 +56,18 @@ namespace OFOPXMLHelper {
         const css::uno::Reference< css::io::XInputStream >& xInStream,
         const css::uno::Reference< css::uno::XComponentContext >& rContext );
 
+    // returns the ContentType for the given name, or empty when not found.
+    // rContentTypes is a sequence containing two entries of type sequence<StringPair>
+    // 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<css::uno::Sequence<css::beans::StringPair>>& 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 b4836634ed2a..0388fae5f473 100644
--- a/oox/source/core/xmlfilterbase.cxx
+++ b/oox/source/core/xmlfilterbase.cxx
@@ -61,6 +61,7 @@
 #include <oox/core/filterdetect.hxx>
 #include <comphelper/storagehelper.hxx>
 #include <comphelper/sequence.hxx>
+#include <comphelper/ofopxmlhelper.hxx>
 
 #include <oox/crypto/DocumentEncryption.hxx>
 #include <tools/date.hxx>
@@ -960,13 +961,6 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStora
     Reference<XRelationshipAccess> xRelations(xDocumentStorage, UNO_QUERY);
     if (xRelations.is())
     {
-        // These are all the custom types we recognize and can preserve.
-        static const std::set<OUString> 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<uno::Sequence<beans::StringPair>> aSeqs = xRelations->getAllRelationships();
 
         std::vector<StreamDataSequence> aCustomFragments;
@@ -986,7 +980,8 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStora
                     sType = aPair.Second;
             }
 
-            if (sCustomTypes.find(sType) != sCustomTypes.end())
+            // Preserve non-standard (i.e. custom) entries.
+            if (!sType.match("http://schemas.openxmlformats.org"))
             {
                 StreamDataSequence aDataSeq;
                 if (importBinaryData(aDataSeq, sTarget))
@@ -1008,7 +1003,7 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStora
         std::vector<uno::Reference<xml::dom::XDocument>> 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<XDocument> xCustDoc = importFragment("customXml/item" + OUString::number(i) + ".xml");
             Reference<XDocument> xCustDocProps = importFragment("customXml/itemProps" + OUString::number(i) + ".xml");
@@ -1025,6 +1020,14 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStora
         aGrabBagProperties["OOXCustomXml"] <<= comphelper::containerToSequence(aCustomXmlDomList);
         aGrabBagProperties["OOXCustomXmlProps"] <<= comphelper::containerToSequence(aCustomXmlDomPropsList);
 
+        // Save the [Content_Types].xml after parsing.
+        uno::Sequence<uno::Sequence<beans::StringPair>> aContentTypeInfo;
+        uno::Reference<io::XInputStream> xInputStream = openInputStream("[Content_Types].xml");
+        if (xInputStream.is())
+            aContentTypeInfo = comphelper::OFOPXMLHelper::ReadContentTypeSequence(xInputStream, getComponentContext());
+
+        aGrabBagProperties["OOXContentTypes"] <<= aContentTypeInfo;
+
         Reference<XComponent> xModel(getModel(), UNO_QUERY);
         oox::core::XmlFilterBase::putPropertiesToDocumentGrabBag(xModel, aGrabBagProperties);
     }
@@ -1045,6 +1048,7 @@ void XmlFilterBase::exportCustomFragments()
     uno::Sequence<StreamDataSequence> customFragments;
     uno::Sequence<OUString> customFragmentTypes;
     uno::Sequence<OUString> customFragmentTargets;
+    uno::Sequence<uno::Sequence<beans::StringPair>> aContentTypes;
 
     uno::Sequence<beans::PropertyValue> propList;
     xPropSet->getPropertyValue(aName) >>= propList;
@@ -1071,6 +1075,10 @@ void XmlFilterBase::exportCustomFragments()
         {
             propList[nProp].Value >>= customFragmentTargets;
         }
+        else if (propName == "OOXContentTypes")
+        {
+            propList[nProp].Value >>= aContentTypes;
+        }
     }
 
     // Expect customXmlDomPropslist.getLength() == customXmlDomlist.getLength().
@@ -1110,10 +1118,16 @@ void XmlFilterBase::exportCustomFragments()
     for (sal_Int32 j = 0; j < customFragments.getLength(); j++)
     {
         addRelation(customFragmentTypes[j], customFragmentTargets[j]);
-        Reference<XOutputStream> xOutStream = openOutputStream(customFragmentTargets[j]);
+        const OUString aFilename = customFragmentTargets[j];
+        Reference<XOutputStream> xOutStream = openOutputStream(aFilename);
         xOutStream->writeBytes(customFragments[j]);
-        // BinaryXInputStream aInStrm(openOutputStream(customFragmentTargets[j]), true);
-        // aInStrm.copyToStream(xOutputStream);
+        uno::Reference<XPropertySet> 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 cddda58e68a5..a04580dcaeae 100644
--- a/package/source/zippackage/ZipPackage.cxx
+++ b/package/source/zippackage/ZipPackage.cxx
@@ -1088,10 +1088,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(1);
-    // 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";
+    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;


More information about the Libreoffice-commits mailing list