diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-11-30 08:48:06 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-11-30 15:35:44 +0100 |
commit | 1a48cdaf91633b354fb1110c566c766a4398fba0 (patch) | |
tree | 18973dc147cfd3f2d8276341593dca00c60e2723 /writerperfect/source/writer/exp | |
parent | 56d79a2d046f08e703ed6498b7c8d15abe057d3a (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.cxx | 98 | ||||
-rw-r--r-- | writerperfect/source/writer/exp/xmlimp.hxx | 7 | ||||
-rw-r--r-- | writerperfect/source/writer/exp/xmlmetai.cxx | 91 | ||||
-rw-r--r-- | writerperfect/source/writer/exp/xmlmetai.hxx | 45 |
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 |