Kaydet (Commit) 8f79f22a authored tarafından Ashod Nakashian's avatar Ashod Nakashian Kaydeden (comit) Jan Holesovsky

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/50856Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarJan Holesovsky <kendy@collabora.com>
üst 4de1c022
...@@ -110,6 +110,38 @@ uno::Sequence< uno::Sequence< beans::StringPair > > ReadContentTypeSequence( ...@@ -110,6 +110,38 @@ uno::Sequence< uno::Sequence< beans::StringPair > > ReadContentTypeSequence(
return ReadSequence_Impl( xInStream, aStringID, CONTENTTYPE_FORMAT, rContext ); 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( void WriteRelationsInfoSequence(
const uno::Reference< io::XOutputStream >& xOutStream, const uno::Reference< io::XOutputStream >& xOutStream,
......
...@@ -56,6 +56,18 @@ namespace OFOPXMLHelper { ...@@ -56,6 +56,18 @@ namespace OFOPXMLHelper {
const css::uno::Reference< css::io::XInputStream >& xInStream, const css::uno::Reference< css::io::XInputStream >& xInStream,
const css::uno::Reference< css::uno::XComponentContext >& rContext ); 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, // writes sequence of elements, where each element is described by sequence of tags,
// where each tag is described by StringPair ( First - name, Second - value ) // where each tag is described by StringPair ( First - name, Second - value )
// the first tag of each element sequence must be "Id" // the first tag of each element sequence must be "Id"
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#include <oox/core/filterdetect.hxx> #include <oox/core/filterdetect.hxx>
#include <comphelper/storagehelper.hxx> #include <comphelper/storagehelper.hxx>
#include <comphelper/sequence.hxx> #include <comphelper/sequence.hxx>
#include <comphelper/ofopxmlhelper.hxx>
#include <oox/crypto/DocumentEncryption.hxx> #include <oox/crypto/DocumentEncryption.hxx>
#include <tools/date.hxx> #include <tools/date.hxx>
...@@ -960,13 +961,6 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStora ...@@ -960,13 +961,6 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStora
Reference<XRelationshipAccess> xRelations(xDocumentStorage, UNO_QUERY); Reference<XRelationshipAccess> xRelations(xDocumentStorage, UNO_QUERY);
if (xRelations.is()) 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(); uno::Sequence<uno::Sequence<beans::StringPair>> aSeqs = xRelations->getAllRelationships();
std::vector<StreamDataSequence> aCustomFragments; std::vector<StreamDataSequence> aCustomFragments;
...@@ -986,7 +980,8 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStora ...@@ -986,7 +980,8 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStora
sType = aPair.Second; 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; StreamDataSequence aDataSeq;
if (importBinaryData(aDataSeq, sTarget)) if (importBinaryData(aDataSeq, sTarget))
...@@ -1008,7 +1003,7 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStora ...@@ -1008,7 +1003,7 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStora
std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomPropsList; std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomPropsList;
//FIXME: Ideally, we should get these the relations, but it seems that is not consistently set. //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. // 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> xCustDoc = importFragment("customXml/item" + OUString::number(i) + ".xml");
Reference<XDocument> xCustDocProps = importFragment("customXml/itemProps" + 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 ...@@ -1025,6 +1020,14 @@ void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStora
aGrabBagProperties["OOXCustomXml"] <<= comphelper::containerToSequence(aCustomXmlDomList); aGrabBagProperties["OOXCustomXml"] <<= comphelper::containerToSequence(aCustomXmlDomList);
aGrabBagProperties["OOXCustomXmlProps"] <<= comphelper::containerToSequence(aCustomXmlDomPropsList); 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); Reference<XComponent> xModel(getModel(), UNO_QUERY);
oox::core::XmlFilterBase::putPropertiesToDocumentGrabBag(xModel, aGrabBagProperties); oox::core::XmlFilterBase::putPropertiesToDocumentGrabBag(xModel, aGrabBagProperties);
} }
...@@ -1045,6 +1048,7 @@ void XmlFilterBase::exportCustomFragments() ...@@ -1045,6 +1048,7 @@ void XmlFilterBase::exportCustomFragments()
uno::Sequence<StreamDataSequence> customFragments; uno::Sequence<StreamDataSequence> customFragments;
uno::Sequence<OUString> customFragmentTypes; uno::Sequence<OUString> customFragmentTypes;
uno::Sequence<OUString> customFragmentTargets; uno::Sequence<OUString> customFragmentTargets;
uno::Sequence<uno::Sequence<beans::StringPair>> aContentTypes;
uno::Sequence<beans::PropertyValue> propList; uno::Sequence<beans::PropertyValue> propList;
xPropSet->getPropertyValue(aName) >>= propList; xPropSet->getPropertyValue(aName) >>= propList;
...@@ -1071,6 +1075,10 @@ void XmlFilterBase::exportCustomFragments() ...@@ -1071,6 +1075,10 @@ void XmlFilterBase::exportCustomFragments()
{ {
propList[nProp].Value >>= customFragmentTargets; propList[nProp].Value >>= customFragmentTargets;
} }
else if (propName == "OOXContentTypes")
{
propList[nProp].Value >>= aContentTypes;
}
} }
// Expect customXmlDomPropslist.getLength() == customXmlDomlist.getLength(). // Expect customXmlDomPropslist.getLength() == customXmlDomlist.getLength().
...@@ -1110,10 +1118,16 @@ void XmlFilterBase::exportCustomFragments() ...@@ -1110,10 +1118,16 @@ void XmlFilterBase::exportCustomFragments()
for (sal_Int32 j = 0; j < customFragments.getLength(); j++) for (sal_Int32 j = 0; j < customFragments.getLength(); j++)
{ {
addRelation(customFragmentTypes[j], customFragmentTargets[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]); xOutStream->writeBytes(customFragments[j]);
// BinaryXInputStream aInStrm(openOutputStream(customFragmentTargets[j]), true); uno::Reference<XPropertySet> xProps(xOutStream, uno::UNO_QUERY);
// aInStrm.copyToStream(xOutputStream); 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));
}
} }
} }
......
...@@ -1088,10 +1088,16 @@ void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno: ...@@ -1088,10 +1088,16 @@ void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno:
// Convert vector into a uno::Sequence // Convert vector into a uno::Sequence
// TODO/LATER: use Default entries in future // TODO/LATER: use Default entries in future
uno::Sequence< beans::StringPair > aDefaultsSequence(1); uno::Sequence< beans::StringPair > aDefaultsSequence(4);
// Add at least the application/xml default entry. // Add at least the standard default entries.
aDefaultsSequence[0].First = "xml"; aDefaultsSequence[0].First = "xml";
aDefaultsSequence[0].Second= "application/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()); uno::Sequence< beans::StringPair > aOverridesSequence(aManList.size());
sal_Int32 nOverSeqLength = 0; sal_Int32 nOverSeqLength = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment