summaryrefslogtreecommitdiff
path: root/writerperfect/source/writer/exp
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2017-11-30 08:48:06 +0100
committerMiklos Vajna <vmiklos@collabora.co.uk>2017-11-30 15:35:44 +0100
commit1a48cdaf91633b354fb1110c566c766a4398fba0 (patch)
tree18973dc147cfd3f2d8276341593dca00c60e2723 /writerperfect/source/writer/exp
parent56d79a2d046f08e703ed6498b7c8d15abe057d3a (diff)
EPUB export: allow overwriting of document metadata
Pick up overrides from <base directory>/<base name>.xmp as a start. Change-Id: Ib64a6bbdadc53633fb1f0d4a7efdde2e3c96b5ef Reviewed-on: https://gerrit.libreoffice.org/45551 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Diffstat (limited to 'writerperfect/source/writer/exp')
-rw-r--r--writerperfect/source/writer/exp/xmlimp.cxx98
-rw-r--r--writerperfect/source/writer/exp/xmlimp.hxx7
-rw-r--r--writerperfect/source/writer/exp/xmlmetai.cxx91
-rw-r--r--writerperfect/source/writer/exp/xmlmetai.hxx45
4 files changed, 222 insertions, 19 deletions
diff --git a/writerperfect/source/writer/exp/xmlimp.cxx b/writerperfect/source/writer/exp/xmlimp.cxx
index bc3b9c7693e4..57f89c870b9a 100644
--- a/writerperfect/source/writer/exp/xmlimp.cxx
+++ b/writerperfect/source/writer/exp/xmlimp.cxx
@@ -12,9 +12,12 @@
#include <initializer_list>
#include <unordered_map>
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <com/sun/star/xml/sax/Parser.hpp>
#include <rtl/uri.hxx>
#include <tools/stream.hxx>
#include <tools/urlobj.hxx>
+#include <unotools/streamwrap.hxx>
#include "xmlfmt.hxx"
#include "xmlictxt.hxx"
@@ -46,26 +49,16 @@ OUString GetMimeType(const OUString &rExtension)
}
/// Picks up a cover image from the base directory.
-OUString FindCoverImage(const OUString &rDocumentBaseURL, OUString &rMimeType, const uno::Sequence<beans::PropertyValue> &rDescriptor)
+OUString FindCoverImage(const OUString &rDocumentBaseURL, OUString &rMimeType, const uno::Sequence<beans::PropertyValue> &rFilterData)
{
OUString aRet;
// See if filter data contains a cover image explicitly.
- uno::Sequence<beans::PropertyValue> aFilterData;
- for (sal_Int32 i = 0; i < rDescriptor.getLength(); ++i)
- {
- if (rDescriptor[i].Name == "FilterData")
- {
- rDescriptor[i].Value >>= aFilterData;
- break;
- }
- }
-
- for (sal_Int32 i = 0; i < aFilterData.getLength(); ++i)
+ for (sal_Int32 i = 0; i < rFilterData.getLength(); ++i)
{
- if (aFilterData[i].Name == "EPUBCoverImage")
+ if (rFilterData[i].Name == "EPUBCoverImage")
{
- aFilterData[i].Value >>= aRet;
+ rFilterData[i].Value >>= aRet;
break;
}
}
@@ -99,7 +92,7 @@ OUString FindCoverImage(const OUString &rDocumentBaseURL, OUString &rMimeType, c
}
catch (const rtl::MalformedUriException &rException)
{
- SAL_WARN("writerfilter", "FindCoverImage: convertRelToAbs() failed:" << rException.getMessage());
+ SAL_WARN("writerperfect", "FindCoverImage: convertRelToAbs() failed:" << rException.getMessage());
}
if (!aRet.isEmpty())
@@ -118,6 +111,57 @@ OUString FindCoverImage(const OUString &rDocumentBaseURL, OUString &rMimeType, c
return aRet;
}
+
+/// Picks up XMP metadata from the base directory.
+void FindXMPMetadata(const uno::Reference<uno::XComponentContext> &xContext, const OUString &rDocumentBaseURL, const uno::Sequence<beans::PropertyValue> &/*rFilterData*/, librevenge::RVNGPropertyList &rMetaData)
+{
+ if (rDocumentBaseURL.isEmpty())
+ return;
+
+ INetURLObject aDocumentBaseURL(rDocumentBaseURL);
+ OUString aURL;
+ try
+ {
+ aURL = rtl::Uri::convertRelToAbs(rDocumentBaseURL, aDocumentBaseURL.GetBase() + ".xmp");
+ }
+ catch (const rtl::MalformedUriException &rException)
+ {
+ SAL_WARN("writerperfect", "FindXMPMetadata: convertRelToAbs() failed:" << rException.getMessage());
+ return;
+ }
+
+ SvFileStream aStream(aURL, StreamMode::READ);
+ if (!aStream.IsOpen())
+ return;
+
+ xml::sax::InputSource aInputSource;
+ uno::Reference<io::XInputStream> xStream(new utl::OStreamWrapper(aStream));
+ aInputSource.aInputStream = xStream;
+ uno::Reference<xml::sax::XParser> xParser = xml::sax::Parser::create(xContext);
+ rtl::Reference<XMPParser> xXMP(new XMPParser());
+ uno::Reference<xml::sax::XDocumentHandler> xDocumentHandler(xXMP.get());
+ xParser->setDocumentHandler(xDocumentHandler);
+ try
+ {
+ xParser->parseStream(aInputSource);
+ }
+ catch (const uno::Exception &rException)
+ {
+ SAL_WARN("writerperfect", "FindXMPMetadata: parseStream() failed:" << rException.Message);
+ return;
+ }
+
+ if (!xXMP->m_aIdentifier.isEmpty())
+ rMetaData.insert("dc:identifier", xXMP->m_aIdentifier.toUtf8().getStr());
+ if (!xXMP->m_aTitle.isEmpty())
+ rMetaData.insert("dc:title", xXMP->m_aTitle.toUtf8().getStr());
+ if (!xXMP->m_aCreator.isEmpty())
+ rMetaData.insert("meta:initial-creator", xXMP->m_aCreator.toUtf8().getStr());
+ if (!xXMP->m_aLanguage.isEmpty())
+ rMetaData.insert("dc:language", xXMP->m_aLanguage.toUtf8().getStr());
+ if (!xXMP->m_aDate.isEmpty())
+ rMetaData.insert("dc:date", xXMP->m_aDate.toUtf8().getStr());
+}
}
/// Handler for <office:body>.
@@ -170,11 +214,22 @@ rtl::Reference<XMLImportContext> XMLOfficeDocContext::CreateChildContext(const O
return nullptr;
}
-XMLImport::XMLImport(librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const uno::Sequence<beans::PropertyValue> &rDescriptor)
- : mrGenerator(rGenerator)
+XMLImport::XMLImport(const uno::Reference<uno::XComponentContext> &xContext, librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const uno::Sequence<beans::PropertyValue> &rDescriptor)
+ : mrGenerator(rGenerator),
+ mxContext(xContext)
{
+ uno::Sequence<beans::PropertyValue> aFilterData;
+ for (sal_Int32 i = 0; i < rDescriptor.getLength(); ++i)
+ {
+ if (rDescriptor[i].Name == "FilterData")
+ {
+ rDescriptor[i].Value >>= aFilterData;
+ break;
+ }
+ }
+
OUString aMimeType;
- OUString aCoverImage = FindCoverImage(rURL, aMimeType, rDescriptor);
+ OUString aCoverImage = FindCoverImage(rURL, aMimeType, aFilterData);
if (!aCoverImage.isEmpty())
{
librevenge::RVNGBinaryData aBinaryData;
@@ -187,6 +242,8 @@ XMLImport::XMLImport(librevenge::RVNGTextInterface &rGenerator, const OUString &
aCoverImageProperties.insert("librevenge:mime-type", aMimeType.toUtf8().getStr());
maCoverImages.append(aCoverImageProperties);
}
+
+ FindXMPMetadata(mxContext, rURL, aFilterData, maMetaData);
}
const librevenge::RVNGPropertyListVector &XMLImport::GetCoverImages()
@@ -194,6 +251,11 @@ const librevenge::RVNGPropertyListVector &XMLImport::GetCoverImages()
return maCoverImages;
}
+const librevenge::RVNGPropertyList &XMLImport::GetMetaData()
+{
+ return maMetaData;
+}
+
rtl::Reference<XMLImportContext> XMLImport::CreateContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &/*xAttribs*/)
{
if (rName == "office:document")
diff --git a/writerperfect/source/writer/exp/xmlimp.hxx b/writerperfect/source/writer/exp/xmlimp.hxx
index b1008f00dbf0..90a9762bb9b6 100644
--- a/writerperfect/source/writer/exp/xmlimp.hxx
+++ b/writerperfect/source/writer/exp/xmlimp.hxx
@@ -16,6 +16,7 @@
#include <librevenge/librevenge.h>
#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#include <cppuhelper/implbase.hxx>
@@ -51,9 +52,12 @@ class XMLImport : public cppu::WeakImplHelper
std::map<OUString, librevenge::RVNGPropertyList> maAutomaticGraphicStyles;
std::map<OUString, librevenge::RVNGPropertyList> maGraphicStyles;
librevenge::RVNGPropertyListVector maCoverImages;
+ /// Author, date, etc -- overwrites what would be from the document out of the box.
+ librevenge::RVNGPropertyList maMetaData;
+ const css::uno::Reference<css::uno::XComponentContext> &mxContext;
public:
- XMLImport(librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const css::uno::Sequence<css::beans::PropertyValue> &rDescriptor);
+ XMLImport(const css::uno::Reference<css::uno::XComponentContext> &xContext, librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const css::uno::Sequence<css::beans::PropertyValue> &rDescriptor);
rtl::Reference<XMLImportContext> CreateContext(const OUString &rName, const css::uno::Reference<css::xml::sax::XAttributeList> &xAttribs);
@@ -73,6 +77,7 @@ public:
std::map<OUString, librevenge::RVNGPropertyList> &GetTableStyles();
std::map<OUString, librevenge::RVNGPropertyList> &GetGraphicStyles();
const librevenge::RVNGPropertyListVector &GetCoverImages();
+ const librevenge::RVNGPropertyList &GetMetaData();
// XDocumentHandler
void SAL_CALL startDocument() override;
diff --git a/writerperfect/source/writer/exp/xmlmetai.cxx b/writerperfect/source/writer/exp/xmlmetai.cxx
index ad39aa8c39f1..09e56c8c2388 100644
--- a/writerperfect/source/writer/exp/xmlmetai.cxx
+++ b/writerperfect/source/writer/exp/xmlmetai.cxx
@@ -131,6 +131,9 @@ void XMLMetaInitialCreatorContext::characters(const OUString &rChars)
XMLMetaDocumentContext::XMLMetaDocumentContext(XMLImport &rImport)
: XMLImportContext(rImport)
{
+ librevenge::RVNGPropertyList::Iter it(mrImport.GetMetaData());
+ for (it.rewind(); it.next();)
+ m_aPropertyList.insert(it.key(), it()->clone());
m_aPropertyList.insert("librevenge:cover-images", mrImport.GetCoverImages());
}
@@ -154,6 +157,94 @@ void XMLMetaDocumentContext::endElement(const OUString &/*rName*/)
mrImport.GetGenerator().setDocumentMetaData(m_aPropertyList);
}
+XMPParser::XMPParser() = default;
+
+XMPParser::~XMPParser() = default;
+
+void XMPParser::startDocument()
+{
+}
+
+void XMPParser::endDocument()
+{
+}
+
+void XMPParser::startElement(const OUString &rName, const uno::Reference<xml::sax::XAttributeList> &/*xAttribs*/)
+{
+ if (rName == "dc:identifier")
+ m_bInIdentifier = true;
+ else if (rName == "dc:title")
+ m_bInTitle = true;
+ else if (rName == "dc:creator")
+ m_bInCreator = true;
+ else if (rName == "dc:language")
+ m_bInLanguage = true;
+ else if (rName == "dc:date")
+ m_bInDate = true;
+ else if (rName == "rdf:li")
+ {
+ if (m_bInTitle)
+ m_bInTitleItem = true;
+ else if (m_bInCreator)
+ m_bInCreatorItem = true;
+ else if (m_bInLanguage)
+ m_bInLanguageItem = true;
+ else if (m_bInDate)
+ m_bInDateItem = true;
+ }
+}
+
+void XMPParser::endElement(const OUString &rName)
+{
+ if (rName == "dc:identifier")
+ m_bInIdentifier = false;
+ else if (rName == "dc:title")
+ m_bInTitle = false;
+ else if (rName == "dc:creator")
+ m_bInCreator = false;
+ else if (rName == "dc:language")
+ m_bInLanguage = false;
+ else if (rName == "dc:date")
+ m_bInDate = false;
+ else if (rName == "rdf:li")
+ {
+ if (m_bInTitle)
+ m_bInTitleItem = false;
+ else if (m_bInCreator)
+ m_bInCreatorItem = false;
+ else if (m_bInLanguage)
+ m_bInLanguageItem = false;
+ else if (m_bInDate)
+ m_bInDateItem = false;
+ }
+}
+
+void XMPParser::characters(const OUString &rChars)
+{
+ if (m_bInIdentifier)
+ m_aIdentifier += rChars;
+ else if (m_bInTitleItem)
+ m_aTitle += rChars;
+ else if (m_bInCreatorItem)
+ m_aCreator += rChars;
+ else if (m_bInLanguageItem)
+ m_aLanguage += rChars;
+ else if (m_bInDateItem)
+ m_aDate += rChars;
+}
+
+void XMPParser::ignorableWhitespace(const OUString &/*rWhitespace*/)
+{
+}
+
+void XMPParser::processingInstruction(const OUString &/*rTarget*/, const OUString &/*rData*/)
+{
+}
+
+void XMPParser::setDocumentLocator(const uno::Reference<xml::sax::XLocator> &/*xLocator*/)
+{
+}
+
} // namespace exp
} // namespace writerperfect
diff --git a/writerperfect/source/writer/exp/xmlmetai.hxx b/writerperfect/source/writer/exp/xmlmetai.hxx
index 12285937a705..a011e6b83184 100644
--- a/writerperfect/source/writer/exp/xmlmetai.hxx
+++ b/writerperfect/source/writer/exp/xmlmetai.hxx
@@ -32,6 +32,51 @@ public:
librevenge::RVNGPropertyList m_aPropertyList;
};
+/// Parses an XMP file.
+class XMPParser: public cppu::WeakImplHelper
+ <
+ css::xml::sax::XDocumentHandler
+ >
+{
+public:
+ explicit XMPParser();
+ virtual ~XMPParser() override;
+
+ // XDocumentHandler
+ virtual void SAL_CALL startDocument() override;
+
+ virtual void SAL_CALL endDocument() override;
+
+ virtual void SAL_CALL startElement(const OUString &aName, const css::uno::Reference<css::xml::sax::XAttributeList> &xAttribs) override;
+
+ virtual void SAL_CALL endElement(const OUString &aName) override;
+
+ virtual void SAL_CALL characters(const OUString &aChars) override;
+
+ virtual void SAL_CALL ignorableWhitespace(const OUString &aWhitespaces) override;
+
+ virtual void SAL_CALL processingInstruction(const OUString &aTarget, const OUString &aData) override;
+
+ virtual void SAL_CALL setDocumentLocator(const css::uno::Reference<css::xml::sax::XLocator> &xLocator) override;
+
+ OUString m_aIdentifier;
+ OUString m_aTitle;
+ OUString m_aCreator;
+ OUString m_aLanguage;
+ OUString m_aDate;
+
+private:
+ bool m_bInIdentifier = false;
+ bool m_bInTitle = false;
+ bool m_bInTitleItem = false;
+ bool m_bInCreator = false;
+ bool m_bInCreatorItem = false;
+ bool m_bInLanguage = false;
+ bool m_bInLanguageItem = false;
+ bool m_bInDate = false;
+ bool m_bInDateItem = false;
+};
+
} // namespace exp
} // namespace writerperfect