diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /writerperfect/source | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'writerperfect/source')
96 files changed, 10451 insertions, 0 deletions
diff --git a/writerperfect/source/calc/MSWorksCalcImportFilter.cxx b/writerperfect/source/calc/MSWorksCalcImportFilter.cxx new file mode 100644 index 000000000..b0118eaad --- /dev/null +++ b/writerperfect/source/calc/MSWorksCalcImportFilter.cxx @@ -0,0 +1,474 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* MSWorksCalcImportFilter: Sets up the filter, and calls DocumentCollector + * to do the actual filtering + * + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <sal/log.hxx> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <sfx2/passwd.hxx> +#include <tools/urlobj.hxx> +#include <ucbhelper/content.hxx> + +#include <libwps/libwps.h> + +#include <DocumentHandlerForOds.hxx> +#include <WPFTEncodingDialog.hxx> +#include <WPFTResMgr.hxx> +#include "MSWorksCalcImportFilter.hxx" +#include <strings.hrc> + +#include <iostream> +#include <map> + +using namespace ::com::sun::star; + +namespace MSWorksCalcImportFilterInternal +{ +/// returns the list of stream name present in a folder +static uno::Reference<sdbc::XResultSet> +getResultSet(const css::uno::Reference<css::ucb::XContent>& xPackageContent) +{ + try + { + if (xPackageContent.is()) + { + ucbhelper::Content packageContent(xPackageContent, + uno::Reference<ucb::XCommandEnvironment>(), + comphelper::getProcessComponentContext()); + uno::Sequence<OUString> lPropNames{ "Title" }; + uno::Reference<sdbc::XResultSet> xResultSet( + packageContent.createCursor(lPropNames, ucbhelper::INCLUDE_DOCUMENTS_ONLY)); + return xResultSet; + } + return uno::Reference<sdbc::XResultSet>(); + } + catch (...) + { + SAL_WARN("writerperfect", + "ignoring Exception in MSWorksCalcImportFilterInternal:getResultSet"); + return uno::Reference<sdbc::XResultSet>(); + } +} + +namespace +{ +/** internal class used to create a structured RVNGInputStream from a list of path and their short names + */ +class FolderStream : public librevenge::RVNGInputStream +{ +public: + //! constructor + explicit FolderStream(const css::uno::Reference<css::ucb::XContent>& xContent) + : m_xContent(xContent) + { + } + + //! add a file + void addFile(OUString const& path, std::string const& shortName) + { + m_nameToPathMap[shortName] = path; + } + /**! reads numbytes data. + + * \return a pointer to the read elements + */ + const unsigned char* read(unsigned long, unsigned long&) override { return nullptr; } + //! returns actual offset position + long tell() override { return 0; } + /*! \brief seeks to an offset position, from actual, beginning or ending position + * \return 0 if ok + */ + int seek(long, librevenge::RVNG_SEEK_TYPE) override { return 1; } + //! returns true if we are at the end of the section/file + bool isEnd() override { return true; } + + /** returns true if the stream is ole + + \sa returns always false*/ + bool isStructured() override { return true; } + /** returns the number of sub streams. + + \sa returns always 2*/ + unsigned subStreamCount() override { return unsigned(m_nameToPathMap.size()); } + /** returns the ith sub streams name */ + const char* subStreamName(unsigned id) override + { + if (m_nameToPathMap.size() < id) + return nullptr; + + std::map<std::string, OUString>::const_iterator it = m_nameToPathMap.begin(); + std::advance(it, id); + return it->first.c_str(); + } + /** returns true if a substream with name exists */ + bool existsSubStream(const char* name) override + { + return name && m_nameToPathMap.find(name) != m_nameToPathMap.end(); + } + /** return a new stream for an OLE zone */ + librevenge::RVNGInputStream* getSubStreamByName(const char* name) override + { + if (m_nameToPathMap.find(name) == m_nameToPathMap.end() || !m_xContent.is()) + return nullptr; + + try + { + const uno::Reference<sdbc::XResultSet> xResultSet = getResultSet(m_xContent); + if (xResultSet.is() && xResultSet->first()) + { + const uno::Reference<ucb::XContentAccess> xContentAccess(xResultSet, + uno::UNO_QUERY_THROW); + const uno::Reference<sdbc::XRow> xRow(xResultSet, uno::UNO_QUERY_THROW); + OUString lPath = m_nameToPathMap.find(name)->second; + do + { + const OUString aTitle(xRow->getString(1)); + if (aTitle != lPath) + continue; + + const uno::Reference<ucb::XContent> xSubContent(xContentAccess->queryContent()); + ucbhelper::Content aSubContent(xSubContent, + uno::Reference<ucb::XCommandEnvironment>(), + comphelper::getProcessComponentContext()); + uno::Reference<io::XInputStream> xInputStream = aSubContent.openStream(); + if (xInputStream.is()) + return new writerperfect::WPXSvInputStream(xInputStream); + break; + } while (xResultSet->next()); + } + } + catch (...) + { + SAL_WARN("writerperfect", "ignoring Exception in " + "MSWorksCalcImportFilterInternal::FolderStream::" + "getSubStreamByName"); + } + + return nullptr; + } + /** return a new stream for an OLE zone */ + librevenge::RVNGInputStream* getSubStreamById(unsigned id) override + { + char const* name = subStreamName(id); + return name ? getSubStreamByName(name) : nullptr; + } + +private: + /// the main container + uno::Reference<ucb::XContent> m_xContent; + /// the map short name to path + std::map<std::string, OUString> m_nameToPathMap; + FolderStream(const FolderStream&) = delete; + FolderStream& operator=(const FolderStream&) = delete; +}; +} +} + +//////////////////////////////////////////////////////////// +bool MSWorksCalcImportFilter::doImportDocument(weld::Window* pParent, + librevenge::RVNGInputStream& rInput, + OdsGenerator& rGenerator, + utl::MediaDescriptor& mediaDescriptor) +{ + libwps::WPSKind kind = libwps::WPS_TEXT; + libwps::WPSCreator creator; + bool needEncoding; + const libwps::WPSConfidence confidence + = libwps::WPSDocument::isFileFormatSupported(&rInput, kind, creator, needEncoding); + + if ((kind != libwps::WPS_SPREADSHEET && kind != libwps::WPS_DATABASE) + || (confidence == libwps::WPS_CONFIDENCE_NONE)) + return false; + std::string fileEncoding; + if (needEncoding) + { + OUString encoding; + // first check if we can find the encoding in the filter options (headless mode) + mediaDescriptor[utl::MediaDescriptor::PROP_FILTEROPTIONS] >>= encoding; + if (!encoding.isEmpty()) // TODO: check if the encoding string is valid + fileEncoding = encoding.toUtf8().getStr(); + else + { + OUString title; + switch (creator) + { + case libwps::WPS_MSWORKS: + title = WpResId(STR_ENCODING_DIALOG_TITLE_MSWORKS); + encoding = "CP850"; + break; + case libwps::WPS_LOTUS: + title = WpResId(STR_ENCODING_DIALOG_TITLE_LOTUS); + encoding = "CP437"; + break; + case libwps::WPS_SYMPHONY: + title = WpResId(STR_ENCODING_DIALOG_TITLE_SYMPHONY); + encoding = "CP437"; + break; + case libwps::WPS_QUATTRO_PRO: + title = WpResId(STR_ENCODING_DIALOG_TITLE_QUATTROPRO); + encoding = "CP437"; + break; + case libwps::WPS_RESERVED_2: + title = WpResId(STR_ENCODING_DIALOG_TITLE_MSMULTIPLAN); + encoding = "CP437"; + break; + default: + SAL_INFO("writerperfect", "unexpected creator: " << creator); + title = WpResId(STR_ENCODING_DIALOG_TITLE); + encoding = "CP437"; + break; + } + + fileEncoding = encoding.toUtf8().getStr(); // set default to the proposed encoding + try + { + writerperfect::WPFTEncodingDialog aDlg(pParent, title, encoding); + if (aDlg.run() == RET_OK) + { + if (!aDlg.GetEncoding().isEmpty()) + fileEncoding = aDlg.GetEncoding().toUtf8().getStr(); + } + // we can fail because we are in headless mode, the user has cancelled conversion, ... + else if (aDlg.hasUserCalledCancel()) + return false; + } + catch (...) + { + SAL_WARN("writerperfect", + "ignoring Exception in MSWorksCalcImportFilter::doImportDocument"); + } + } + } + OString aUtf8Passwd; + if (confidence == libwps::WPS_CONFIDENCE_SUPPORTED_ENCRYPTION) + { + OUString sPassword; + // now check if we can find the password in the properties + // (just in case, "soffice --headless" adds an option to send password) + mediaDescriptor[utl::MediaDescriptor::PROP_PASSWORD] >>= sPassword; + if (!sPassword.isEmpty()) + aUtf8Passwd = OUStringToOString(sPassword, RTL_TEXTENCODING_UTF8); + else + { + // ok, ask the user for a password + try + { + SfxPasswordDialog aPasswdDlg(pParent); + aPasswdDlg.SetMinLen(1); + if (!aPasswdDlg.run()) + return false; + OUString aPasswd = aPasswdDlg.GetPassword(); + aUtf8Passwd = OUStringToOString(aPasswd, RTL_TEXTENCODING_UTF8); + } + catch (...) + { + return false; + } + } + } + return libwps::WPS_OK + == libwps::WPSDocument::parse(&rInput, &rGenerator, + confidence == libwps::WPS_CONFIDENCE_SUPPORTED_ENCRYPTION + ? aUtf8Passwd.getStr() + : nullptr, + fileEncoding.c_str()); +} + +//XExtendedFilterDetection +sal_Bool +MSWorksCalcImportFilter::filter(const css::uno::Sequence<css::beans::PropertyValue>& rDescriptor) +{ + OUString sUrl; + css::uno::Reference<css::io::XInputStream> xInputStream; + css::uno::Reference<ucb::XContent> xContent; + css::uno::Reference<css::awt::XWindow> xDialogParent; + + for (const auto& rValue : rDescriptor) + { + if (rValue.Name == "InputStream") + rValue.Value >>= xInputStream; + else if (rValue.Name == "UCBContent") + rValue.Value >>= xContent; + else if (rValue.Name == "FileName" || rValue.Name == "URL") + rValue.Value >>= sUrl; + else if (rValue.Name == "ParentWindow") + rValue.Value >>= xDialogParent; + } + + if (!getXContext().is() || !xInputStream.is()) + { + OSL_ASSERT(false); + return false; + } + + // An XML import service: what we push sax messages to... + css::uno::Reference<XInterface> xInternalFilter + = getXContext()->getServiceManager()->createInstanceWithContext( + writerperfect::DocumentHandlerFor<OdsGenerator>::name(), getXContext()); + assert(xInternalFilter); + css::uno::Reference<css::xml::sax::XFastDocumentHandler> xInternalHandler(xInternalFilter, + css::uno::UNO_QUERY); + assert(xInternalHandler); + + // The XImporter sets up an empty target document for XDocumentHandler to write to... + css::uno::Reference<css::document::XImporter> xImporter(xInternalHandler, css::uno::UNO_QUERY); + assert(xImporter); + xImporter->setTargetDocument(getTargetDocument()); + + // OO Graphics Handler: abstract class to handle document SAX messages, concrete implementation here + // writes to in-memory target doc + writerperfect::DocumentHandler aHandler( + new SvXMLLegacyToFastDocHandler(static_cast<SvXMLImport*>(xInternalHandler.get()))); + + writerperfect::WPXSvInputStream input(xInputStream); + OdsGenerator exporter; + exporter.addDocumentHandler(&aHandler, ODF_FLAT_XML); + doRegisterHandlers(exporter); + + utl::MediaDescriptor aDescriptor(rDescriptor); + try + { + // time to check if the file is a WK3 file and a FM3 file is + // present + bool checkForFM3 = false; + if (input.seek(0, librevenge::RVNG_SEEK_SET) == 0 && xContent.is() + && INetURLObject(sUrl).getExtension().equalsIgnoreAsciiCase("WK3")) + { + // check if the file header corresponds to a .wk3 file + unsigned long numBytesRead; + const unsigned char* data = input.read(6, numBytesRead); + if (data && numBytesRead == 6 && data[0] == 0 && data[1] == 0 && data[2] == 0x1a + && data[3] == 0 && data[4] < 2 && data[5] == 0x10) + checkForFM3 = true; + } + if (checkForFM3) + { + // check if the format file exists + const css::uno::Reference<container::XChild> xChild(xContent, uno::UNO_QUERY); + if (xChild.is()) + { + OUString sWM3Name; + OUString sFM3Name; + const css::uno::Reference<ucb::XContent> xPackageContent(xChild->getParent(), + uno::UNO_QUERY); + uno::Reference<sdbc::XResultSet> xResultSet + = MSWorksCalcImportFilterInternal::getResultSet(xPackageContent); + if (xResultSet.is() && xResultSet->first()) + { + const uno::Reference<ucb::XContentAccess> xContentAccess(xResultSet, + uno::UNO_QUERY_THROW); + const uno::Reference<sdbc::XRow> xRow(xResultSet, uno::UNO_QUERY_THROW); + INetURLObject aTmpUrl(sUrl); + sWM3Name = aTmpUrl.getName(INetURLObject::LAST_SEGMENT, true, + INetURLObject::DecodeMechanism::WithCharset); + aTmpUrl.setExtension(u"FM3"); + const OUString& sTestFM3Name + = aTmpUrl.getName(INetURLObject::LAST_SEGMENT, true, + INetURLObject::DecodeMechanism::WithCharset); + do + { + const OUString& aTitle(xRow->getString(1)); + if (aTitle.equalsIgnoreAsciiCase(sTestFM3Name)) + sFM3Name = aTitle; + } while (xResultSet->next() && sFM3Name.isEmpty()); + } + if (!sFM3Name.isEmpty()) + { + MSWorksCalcImportFilterInternal::FolderStream structuredInput(xPackageContent); + structuredInput.addFile(sWM3Name, "WK3"); + structuredInput.addFile(sFM3Name, "FM3"); + + libwps::WPSKind kind = libwps::WPS_TEXT; + libwps::WPSCreator creator; + bool needEncoding; + const libwps::WPSConfidence confidence + = libwps::WPSDocument::isFileFormatSupported(&structuredInput, kind, + creator, needEncoding); + if (confidence != libwps::WPS_CONFIDENCE_NONE) + return doImportDocument(Application::GetFrameWeld(xDialogParent), + structuredInput, exporter, aDescriptor); + } + } + } + } + catch (...) + { + } + + return doImportDocument(Application::GetFrameWeld(xDialogParent), input, exporter, aDescriptor); +} + +bool MSWorksCalcImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, + OUString& rTypeName) +{ + libwps::WPSKind kind = libwps::WPS_TEXT; + libwps::WPSCreator creator; + bool needEncoding; + const libwps::WPSConfidence confidence + = libwps::WPSDocument::isFileFormatSupported(&rInput, kind, creator, needEncoding); + + if ((kind == libwps::WPS_SPREADSHEET || kind == libwps::WPS_DATABASE) + && confidence != libwps::WPS_CONFIDENCE_NONE) + { + switch (creator) + { + case libwps::WPS_MSWORKS: + rTypeName = "calc_MS_Works_Document"; + break; + case libwps::WPS_LOTUS: + case libwps::WPS_SYMPHONY: + rTypeName = "calc_WPS_Lotus_Document"; + break; + case libwps::WPS_QUATTRO_PRO: + rTypeName = "calc_WPS_QPro_Document"; + break; + case libwps::WPS_RESERVED_2: + rTypeName = "calc_MS_Multiplan"; + break; + default: + break; + } + } + + return !rTypeName.isEmpty(); +} + +void MSWorksCalcImportFilter::doRegisterHandlers(OdsGenerator&) {} + +// XServiceInfo +OUString SAL_CALL MSWorksCalcImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Calc.MSWorksCalcImportFilter"; +} + +sal_Bool SAL_CALL MSWorksCalcImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL MSWorksCalcImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Calc_MSWorksCalcImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new MSWorksCalcImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/calc/MSWorksCalcImportFilter.hxx b/writerperfect/source/calc/MSWorksCalcImportFilter.hxx new file mode 100644 index 000000000..d0ce3e1fc --- /dev/null +++ b/writerperfect/source/calc/MSWorksCalcImportFilter.hxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <DocumentHandlerForOds.hxx> +#include <ImportFilter.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class MSWorksCalcImportFilter : public writerperfect::ImportFilter<OdsGenerator> +{ +public: + explicit MSWorksCalcImportFilter( + const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdsGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + //XFilter + virtual sal_Bool SAL_CALL + filter(const css::uno::Sequence<css::beans::PropertyValue>& rDescriptor) override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdsGenerator& rGenerator, utl::MediaDescriptor&) override; + virtual void doRegisterHandlers(OdsGenerator& rGenerator) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/calc/MWAWCalcImportFilter.cxx b/writerperfect/source/calc/MWAWCalcImportFilter.cxx new file mode 100644 index 000000000..186084b17 --- /dev/null +++ b/writerperfect/source/calc/MWAWCalcImportFilter.cxx @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* MWAWCalcImportFilter: Sets up the filter, and calls DocumentCollector + * to do the actual filtering + * + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libmwaw/libmwaw.hxx> + +#include "MWAWCalcImportFilter.hxx" + +static bool handleEmbeddedMWAWGraphicObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdgGenerator exporter; + exporter.addDocumentHandler(pHandler, streamType); + return MWAWDocument::decodeGraphic(data, &exporter); +} + +static bool handleEmbeddedMWAWSpreadsheetObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdsGenerator exporter; + exporter.addDocumentHandler(pHandler, streamType); + return MWAWDocument::decodeSpreadsheet(data, &exporter); +} + +bool MWAWCalcImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdsGenerator& rGenerator, utl::MediaDescriptor&) +{ + return MWAWDocument::MWAW_R_OK == MWAWDocument::parse(&rInput, &rGenerator); +} + +bool MWAWCalcImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + rTypeName.clear(); + + MWAWDocument::Type docType = MWAWDocument::MWAW_T_UNKNOWN; + MWAWDocument::Kind docKind = MWAWDocument::MWAW_K_UNKNOWN; + const MWAWDocument::Confidence confidence + = MWAWDocument::isFileFormatSupported(&rInput, docType, docKind); + + if (confidence == MWAWDocument::MWAW_C_EXCELLENT) + { + switch (docKind) + { + case MWAWDocument::MWAW_K_DATABASE: + switch (docType) + { + case MWAWDocument::MWAW_T_CLARISWORKS: + rTypeName = "calc_ClarisWorks"; + break; + case MWAWDocument::MWAW_T_MICROSOFTWORKS: + rTypeName = "calc_Mac_Works"; + break; + default: + rTypeName = "MWAW_Database"; + break; + } + break; + case MWAWDocument::MWAW_K_SPREADSHEET: + switch (docType) + { + case MWAWDocument::MWAW_T_CLARISRESOLVE: + rTypeName = "calc_Claris_Resolve"; + break; + case MWAWDocument::MWAW_T_CLARISWORKS: + rTypeName = "calc_ClarisWorks"; + break; + case MWAWDocument::MWAW_T_MICROSOFTWORKS: + rTypeName = "calc_Mac_Works"; + break; + default: + rTypeName = "MWAW_Spreadsheet"; + break; + } + break; + default: + break; + } + } + + return !rTypeName.isEmpty(); +} + +void MWAWCalcImportFilter::doRegisterHandlers(OdsGenerator& rGenerator) +{ + rGenerator.registerEmbeddedObjectHandler("image/mwaw-odg", &handleEmbeddedMWAWGraphicObject); + rGenerator.registerEmbeddedObjectHandler("image/mwaw-ods", + &handleEmbeddedMWAWSpreadsheetObject); +} + +// XServiceInfo +OUString SAL_CALL MWAWCalcImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Calc.MWAWCalcImportFilter"; +} + +sal_Bool SAL_CALL MWAWCalcImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL MWAWCalcImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Calc_MWAWCalcImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new MWAWCalcImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/calc/MWAWCalcImportFilter.hxx b/writerperfect/source/calc/MWAWCalcImportFilter.hxx new file mode 100644 index 000000000..aa574315d --- /dev/null +++ b/writerperfect/source/calc/MWAWCalcImportFilter.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <DocumentHandlerForOds.hxx> +#include <ImportFilter.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class MWAWCalcImportFilter : public writerperfect::ImportFilter<OdsGenerator> +{ +public: + explicit MWAWCalcImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdsGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdsGenerator& rGenerator, utl::MediaDescriptor&) override; + virtual void doRegisterHandlers(OdsGenerator& rGenerator) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/calc/NumbersImportFilter.cxx b/writerperfect/source/calc/NumbersImportFilter.cxx new file mode 100644 index 000000000..813684361 --- /dev/null +++ b/writerperfect/source/calc/NumbersImportFilter.cxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* NumbersImportFilter: Sets up the filter, and calls DocumentCollector + * to do the actual filtering + * + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <libetonyek/libetonyek.h> + +#include <cppuhelper/supportsservice.hxx> + +#include "NumbersImportFilter.hxx" + +using libetonyek::EtonyekDocument; + +bool NumbersImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdsGenerator& rGenerator, utl::MediaDescriptor&) +{ + return EtonyekDocument::parse(&rInput, &rGenerator); +} + +bool NumbersImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + EtonyekDocument::Type type = EtonyekDocument::TYPE_UNKNOWN; + const EtonyekDocument::Confidence confidence = EtonyekDocument::isSupported(&rInput, &type); + if ((confidence == EtonyekDocument::CONFIDENCE_EXCELLENT) + && (type == EtonyekDocument::TYPE_NUMBERS)) + { + rTypeName = "calc_AppleNumbers"; + return true; + } + + return false; +} + +void NumbersImportFilter::doRegisterHandlers(OdsGenerator&) {} + +// XServiceInfo +OUString SAL_CALL NumbersImportFilter::getImplementationName() +{ + return "org.libreoffice.comp.Calc.NumbersImportFilter"; +} + +sal_Bool SAL_CALL NumbersImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL NumbersImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_Calc_NumbersImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new NumbersImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/calc/NumbersImportFilter.hxx b/writerperfect/source/calc/NumbersImportFilter.hxx new file mode 100644 index 000000000..96db0b689 --- /dev/null +++ b/writerperfect/source/calc/NumbersImportFilter.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <DocumentHandlerForOds.hxx> +#include <ImportFilter.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class NumbersImportFilter : public writerperfect::ImportFilter<OdsGenerator> +{ +public: + explicit NumbersImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdsGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdsGenerator& rGenerator, utl::MediaDescriptor&) override; + virtual void doRegisterHandlers(OdsGenerator& rGenerator) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/calc/StarOfficeCalcImportFilter.cxx b/writerperfect/source/calc/StarOfficeCalcImportFilter.cxx new file mode 100644 index 000000000..de7e30e44 --- /dev/null +++ b/writerperfect/source/calc/StarOfficeCalcImportFilter.cxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libstaroffice/libstaroffice.hxx> + +#include "StarOfficeCalcImportFilter.hxx" + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::XInterface; + +static bool handleEmbeddedSTOFFGraphicObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdgGenerator exporter; + exporter.addDocumentHandler(pHandler, streamType); + return STOFFDocument::decodeGraphic(data, &exporter); +} + +static bool handleEmbeddedSTOFFSpreadsheetObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdsGenerator exporter; + exporter.addDocumentHandler(pHandler, streamType); + return STOFFDocument::decodeSpreadsheet(data, &exporter); +} + +bool StarOfficeCalcImportFilter::doImportDocument(weld::Window*, + librevenge::RVNGInputStream& rInput, + OdsGenerator& rGenerator, utl::MediaDescriptor&) +{ + return STOFFDocument::STOFF_R_OK == STOFFDocument::parse(&rInput, &rGenerator); +} + +bool StarOfficeCalcImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, + OUString& rTypeName) +{ + rTypeName.clear(); + STOFFDocument::Kind docKind = STOFFDocument::STOFF_K_UNKNOWN; + const STOFFDocument::Confidence confidence + = STOFFDocument::isFileFormatSupported(&rInput, docKind); + if (confidence == STOFFDocument::STOFF_C_EXCELLENT + || confidence == STOFFDocument::STOFF_C_SUPPORTED_ENCRYPTION) + { + switch (docKind) + { + case STOFFDocument::STOFF_K_DATABASE: + case STOFFDocument::STOFF_K_SPREADSHEET: + rTypeName = "StarOffice_Spreadsheet"; + break; + default: + break; + } + } + + return !rTypeName.isEmpty(); +} + +void StarOfficeCalcImportFilter::doRegisterHandlers(OdsGenerator& rGenerator) +{ + rGenerator.registerEmbeddedObjectHandler("image/stoff-odg", &handleEmbeddedSTOFFGraphicObject); + rGenerator.registerEmbeddedObjectHandler("image/stoff-ods", + &handleEmbeddedSTOFFSpreadsheetObject); +} + +// XServiceInfo +OUString SAL_CALL StarOfficeCalcImportFilter::getImplementationName() +{ + return "org.libreoffice.comp.Calc.StarOfficeCalcImportFilter"; +} + +sal_Bool SAL_CALL StarOfficeCalcImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence<OUString> SAL_CALL StarOfficeCalcImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_Calc_StarOfficeCalcImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new StarOfficeCalcImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/calc/StarOfficeCalcImportFilter.hxx b/writerperfect/source/calc/StarOfficeCalcImportFilter.hxx new file mode 100644 index 000000000..0b11e5166 --- /dev/null +++ b/writerperfect/source/calc/StarOfficeCalcImportFilter.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <DocumentHandlerForOds.hxx> +#include <ImportFilter.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class StarOfficeCalcImportFilter : public writerperfect::ImportFilter<OdsGenerator> +{ +public: + explicit StarOfficeCalcImportFilter( + const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdsGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdsGenerator& rGenerator, utl::MediaDescriptor&) override; + virtual void doRegisterHandlers(OdsGenerator& rGenerator) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/calc/wpftcalc.component b/writerperfect/source/calc/wpftcalc.component new file mode 100644 index 000000000..404d09b6c --- /dev/null +++ b/writerperfect/source/calc/wpftcalc.component @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.Calc.MSWorksCalcImportFilter" + constructor="com_sun_star_comp_Calc_MSWorksCalcImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="com.sun.star.comp.Calc.MWAWCalcImportFilter" + constructor="com_sun_star_comp_Calc_MWAWCalcImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="org.libreoffice.comp.Calc.NumbersImportFilter" + constructor="org_libreoffice_comp_Calc_NumbersImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="org.libreoffice.comp.Calc.StarOfficeCalcImportFilter" + constructor="org_libreoffice_comp_Calc_StarOfficeCalcImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> +</component> diff --git a/writerperfect/source/common/DirectoryStream.cxx b/writerperfect/source/common/DirectoryStream.cxx new file mode 100644 index 000000000..28c38daa6 --- /dev/null +++ b/writerperfect/source/common/DirectoryStream.cxx @@ -0,0 +1,221 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* writerperfect + * Version: MPL 2.0 / LGPLv2.1+ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Major Contributor(s): + * Copyright (C) 2007 Fridrich Strba (fridrich.strba@bluewin.ch) + * + * For minor contributions see the git repository. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU Lesser General Public License Version 2.1 or later + * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are + * applicable instead of those above. + * + * For further information visit http://libwpd.sourceforge.net + */ + +#include <memory> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#include <comphelper/processfactory.hxx> + +#include <rtl/ustring.hxx> + +#include <ucbhelper/content.hxx> + +#include <DirectoryStream.hxx> +#include <WPXSvInputStream.hxx> + +namespace io = com::sun::star::io; +namespace sdbc = com::sun::star::sdbc; +namespace ucb = com::sun::star::ucb; +namespace uno = com::sun::star::uno; + +namespace writerperfect +{ +namespace +{ +uno::Reference<io::XInputStream> findStream(ucbhelper::Content& rContent, std::u16string_view rName) +{ + uno::Reference<io::XInputStream> xInputStream; + + uno::Sequence<OUString> lPropNames{ "Title" }; + try + { + const uno::Reference<sdbc::XResultSet> xResultSet( + rContent.createCursor(lPropNames, ucbhelper::INCLUDE_DOCUMENTS_ONLY)); + if (xResultSet->first()) + { + const uno::Reference<ucb::XContentAccess> xContentAccess(xResultSet, + uno::UNO_QUERY_THROW); + const uno::Reference<sdbc::XRow> xRow(xResultSet, uno::UNO_QUERY_THROW); + do + { + const OUString aTitle(xRow->getString(1)); + if (aTitle == rName) + { + const uno::Reference<ucb::XContent> xSubContent(xContentAccess->queryContent()); + ucbhelper::Content aSubContent(xSubContent, + uno::Reference<ucb::XCommandEnvironment>(), + comphelper::getProcessComponentContext()); + xInputStream = aSubContent.openStream(); + break; + } + } while (xResultSet->next()); + } + } + catch (const uno::RuntimeException&) + { + // ignore + } + catch (const uno::Exception&) + { + // ignore + } + + return xInputStream; +} +} + +struct DirectoryStream::Impl +{ + explicit Impl(const uno::Reference<ucb::XContent>& rxContent); + + uno::Reference<ucb::XContent> xContent; +}; + +DirectoryStream::Impl::Impl(const uno::Reference<ucb::XContent>& rxContent) + : xContent(rxContent) +{ +} + +DirectoryStream::DirectoryStream(const css::uno::Reference<css::ucb::XContent>& xContent) + : m_pImpl(isDirectory(xContent) ? new Impl(xContent) : nullptr) +{ +} + +DirectoryStream::~DirectoryStream() {} + +bool DirectoryStream::isDirectory(const css::uno::Reference<css::ucb::XContent>& xContent) +{ + try + { + if (!xContent.is()) + return false; + + ucbhelper::Content aContent(xContent, uno::Reference<ucb::XCommandEnvironment>(), + comphelper::getProcessComponentContext()); + return aContent.isFolder(); + } + catch (...) + { + return false; + } +} + +std::unique_ptr<DirectoryStream> +DirectoryStream::createForParent(const css::uno::Reference<css::ucb::XContent>& xContent) +{ + try + { + if (!xContent.is()) + return nullptr; + + std::unique_ptr<DirectoryStream> pDir; + + const uno::Reference<css::container::XChild> xChild(xContent, uno::UNO_QUERY); + if (xChild.is()) + { + const uno::Reference<ucb::XContent> xDirContent(xChild->getParent(), uno::UNO_QUERY); + if (xDirContent.is()) + { + pDir = std::make_unique<DirectoryStream>(xDirContent); + if (!pDir->isStructured()) + pDir.reset(); + } + } + + return pDir; + } + catch (...) + { + return nullptr; + } +} + +css::uno::Reference<css::ucb::XContent> DirectoryStream::getContent() const +{ + if (!m_pImpl) + return css::uno::Reference<css::ucb::XContent>(); + return m_pImpl->xContent; +} + +bool DirectoryStream::isStructured() { return m_pImpl != nullptr; } + +unsigned DirectoryStream::subStreamCount() +{ + // TODO: implement me + return 0; +} + +const char* DirectoryStream::subStreamName(unsigned /* id */) +{ + // TODO: implement me + return nullptr; +} + +bool DirectoryStream::existsSubStream(const char* /* name */) +{ + // TODO: implement me + return false; +} + +librevenge::RVNGInputStream* DirectoryStream::getSubStreamByName(const char* const pName) +{ + if (!m_pImpl) + return nullptr; + + ucbhelper::Content aContent(m_pImpl->xContent, uno::Reference<ucb::XCommandEnvironment>(), + comphelper::getProcessComponentContext()); + const uno::Reference<io::XInputStream> xInputStream( + findStream(aContent, OUString::createFromAscii(pName))); + if (xInputStream.is()) + return new WPXSvInputStream(xInputStream); + + return nullptr; +} + +librevenge::RVNGInputStream* DirectoryStream::getSubStreamById(unsigned /* id */) +{ + // TODO: implement me + return nullptr; +} + +const unsigned char* DirectoryStream::read(unsigned long, unsigned long& nNumBytesRead) +{ + nNumBytesRead = 0; + return nullptr; +} + +int DirectoryStream::seek(long, librevenge::RVNG_SEEK_TYPE) { return -1; } + +long DirectoryStream::tell() { return 0; } + +bool DirectoryStream::isEnd() { return true; } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/common/DocumentHandler.cxx b/writerperfect/source/common/DocumentHandler.cxx new file mode 100644 index 000000000..6b5ffe58a --- /dev/null +++ b/writerperfect/source/common/DocumentHandler.cxx @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * For further information visit http://libwpd.sourceforge.net + */ + +#include <DocumentHandler.hxx> + +#include <string.h> + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> + +#include <xmloff/attrlist.hxx> +#include <xmloff/xmlimp.hxx> + +namespace writerperfect +{ +const unsigned char librvng_utf8_skip_data[256] + = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1 }; + +static const char* librvng_utf8_next_char(const char* p) +{ + return p + librvng_utf8_skip_data[*reinterpret_cast<unsigned char const*>(p)]; +} + +static void unescapeXML(const char* s, const unsigned long sz, librevenge::RVNGString& res) +{ + const char* p = s; + const char* const end = p + sz; + while (p != end) + { + const char* const next = librvng_utf8_next_char(p); + if (next > end) + { + // oops, the string is invalid + break; + } + if (p + 4 <= end && p + 1 == next && *p == '&') + { + // look for & , < , > , ' , " + bool escapedChar = false; + switch (*(p + 1)) + { + case 'a': + if (p + 5 <= end && strncmp(p, "&", 5) == 0) + { + res.append('&'); + p += 5; + escapedChar = true; + } + else if (p + 6 <= end && strncmp(p, "'", 6) == 0) + { + res.append('\''); + p += 6; + escapedChar = true; + } + break; + case 'g': + if (strncmp(p, ">", 4) == 0) + { + res.append('>'); + p += 4; + escapedChar = true; + } + break; + case 'l': + if (strncmp(p, "<", 4) == 0) + { + res.append('<'); + p += 4; + escapedChar = true; + } + break; + case 'q': + if (p + 6 <= end && strncmp(p, """, 6) == 0) + { + res.append('"'); + p += 6; + escapedChar = true; + } + break; + default: + break; + } + if (escapedChar) + continue; + } + + while (p != next) + { + res.append(*p); + ++p; + } + p = next; + } +} + +using com::sun::star::uno::Reference; +using com::sun::star::xml::sax::XAttributeList; +using com::sun::star::xml::sax::XDocumentHandler; + +DocumentHandler::DocumentHandler(Reference<XDocumentHandler> const& xHandler) + : mxHandler(xHandler) +{ + if (SvXMLImport* pFastHandler = dynamic_cast<SvXMLImport*>(mxHandler.get())) + mxHandler.set(new SvXMLLegacyToFastDocHandler(pFastHandler)); +} + +void DocumentHandler::startDocument() { mxHandler->startDocument(); } + +void DocumentHandler::endDocument() { mxHandler->endDocument(); } + +void DocumentHandler::startElement(const char* psName, + const librevenge::RVNGPropertyList& xPropList) +{ + rtl::Reference<SvXMLAttributeList> pAttrList = new SvXMLAttributeList(); + librevenge::RVNGPropertyList::Iter i(xPropList); + for (i.rewind(); i.next();) + { + // filter out librevenge elements + if (strncmp(i.key(), "librevenge", 10) != 0) + { + size_t keyLength = strlen(i.key()); + OUString sName(i.key(), keyLength, RTL_TEXTENCODING_UTF8); + OUString sValue(i()->getStr().cstr(), i()->getStr().len(), RTL_TEXTENCODING_UTF8); + + // libodfgen xml-encodes some attribute's value, so check if the value is encoded or not + for (int j = 0; j < 9; ++j) + { + // list of the encoded attributes followed by their lengths + static char const* listEncoded[9] + = { "draw:name", "svg:font-family", "style:condition", + "style:num-prefix", "style:num-suffix", "table:formula", + "text:bullet-char", "text:label", "xlink:href" }; + static size_t const listEncodedLength[9] = { 9, 15, 15, 16, 16, 13, 16, 10, 10 }; + if (keyLength == listEncodedLength[j] + && strncmp(i.key(), listEncoded[j], keyLength) == 0) + { + librevenge::RVNGString decodedValue(""); + unescapeXML(i()->getStr().cstr(), + static_cast<unsigned long>(i()->getStr().len()), decodedValue); + sValue + = OUString(decodedValue.cstr(), decodedValue.len(), RTL_TEXTENCODING_UTF8); + break; + } + } + pAttrList->AddAttribute(sName, sValue); + } + } + + OUString sElementName(psName, strlen(psName), RTL_TEXTENCODING_UTF8); + mxHandler->startElement(sElementName, pAttrList); +} + +void DocumentHandler::endElement(const char* psName) +{ + OUString sElementName(psName, strlen(psName), RTL_TEXTENCODING_UTF8); + mxHandler->endElement(sElementName); +} + +void DocumentHandler::characters(const librevenge::RVNGString& sCharacters) +{ + OUString sCharU16(sCharacters.cstr(), strlen(sCharacters.cstr()), RTL_TEXTENCODING_UTF8); + mxHandler->characters(sCharU16); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/common/WPFTEncodingDialog.cxx b/writerperfect/source/common/WPFTEncodingDialog.cxx new file mode 100644 index 000000000..b0c955481 --- /dev/null +++ b/writerperfect/source/common/WPFTEncodingDialog.cxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <cstddef> +#include <string_view> +#include <utility> + +#include <WPFTEncodingDialog.hxx> + +namespace writerperfect +{ +namespace +{ +std::pair<std::u16string_view, std::u16string_view> const s_encodings[] + = { { u"MacArabic", u"Arabic (Apple Macintosh)" }, + { u"CP864", u"Arabic (DOS/OS2-864)" }, + { u"CP1006", u"Arabic (IBM-1006)" }, + { u"CP1256", u"Arabic (Windows-1256)" }, + { u"CP775", u"Baltic (DOS/OS2-775)" }, + { u"CP1257", u"Baltic (Windows-1257)" }, + { u"MacCeltic", u"Celtic (Apple Macintosh)" }, + { u"MacCyrillic", u"Cyrillic (Apple Macintosh)" }, + { u"CP855", u"Cyrillic (DOS/OS2-855)" }, + { u"CP866", u"Cyrillic (DOS/OS2-866/Russian)" }, + { u"CP1251", u"Cyrillic (Windows-1251)" }, + { u"MacCEurope", u"Eastern Europe (Apple Macintosh)" }, + { u"MacCroatian", u"Eastern Europe (Apple Macintosh/Croatian)" }, + { u"MacRomanian", u"Eastern Europe (Apple Macintosh/Romanian)" }, + { u"CP852", u"Eastern Europe (DOS/OS2-852)" }, + { u"CP1250", u"Eastern Europe (Windows-1250/WinLatin 2)" }, + { u"MacGreek", u"Greek (Apple Macintosh)" }, + { u"CP737", u"Greek (DOS/OS2-737)" }, + { u"CP869", u"Greek (DOS/OS2-869/Greek-2)" }, + { u"CP875", u"Greek (DOS/OS2-875)" }, + { u"CP1253", u"Greek (Windows-1253)" }, + { u"MacHebrew", u"Hebrew (Apple Macintosh)" }, + { u"CP424", u"Hebrew (DOS/OS2-424)" }, + { u"CP856", u"Hebrew (DOS/OS2-856)" }, + { u"CP862", u"Hebrew (DOS/OS2-862)" }, + { u"CP1255", u"Hebrew (Windows-1255)" }, + { u"CP500", u"International (DOS/OS2-500)" }, + { u"CP932", u"Japanese (Windows-932)" }, + { u"MacThai", u"Thai (Apple Macintosh)" }, + { u"CP874", u"Thai (DOS/OS2-874)" }, + { u"CP950", u"Traditional Chinese (Windows-950)" }, + { u"MacTurkish", u"Turkish (Apple Macintosh)" }, + { u"CP857", u"Turkish (DOS/OS2-857)" }, + { u"CP1026", u"Turkish (DOS/OS2-1026)" }, + { u"CP1254", u"Turkish (Windows-1254)" }, + { u"CP1258", u"Vietnamese (Windows-1258)" }, + { u"MacRoman", u"Western Europe (Apple Macintosh)" }, + { u"MacIceland", u"Western Europe (Apple Macintosh/Icelandic)" }, + { u"CP037", u"Western Europe (DOS/OS2-037/US-Canada)" }, + { u"CP437", u"Western Europe (DOS/OS2-437/US)" }, + { u"CP850", u"Western Europe (DOS/OS2-850)" }, + { u"CP860", u"Western Europe (DOS/OS2-860/Portuguese)" }, + { u"CP861", u"Western Europe (DOS/OS2-861/Icelandic)" }, + { u"CP863", u"Western Europe (DOS/OS2-863/French)" }, + { u"CP865", u"Western Europe (DOS/OS2-865/Nordic)" }, + { u"CP1252", u"Western Europe (Windows-1252/WinLatin 1)" } }; + +std::size_t const numEncodings = SAL_N_ELEMENTS(s_encodings); + +void insertEncodings(weld::ComboBox& box) +{ + for (std::size_t i = 0; i < numEncodings; ++i) + box.append(OUString(s_encodings[i].first), OUString(s_encodings[i].second)); +} + +void selectEncoding(weld::ComboBox& box, const OUString& encoding) { box.set_active_id(encoding); } + +OUString getEncoding(const weld::ComboBox& box) { return box.get_active_id(); } +} + +WPFTEncodingDialog::WPFTEncodingDialog(weld::Window* pParent, const OUString& title, + const OUString& encoding) + : GenericDialogController(pParent, "writerperfect/ui/wpftencodingdialog.ui", + "WPFTEncodingDialog") + , m_userHasCancelled(false) + , m_xLbCharset(m_xBuilder->weld_combo_box("comboboxtext")) + , m_xBtnOk(m_xBuilder->weld_button("ok")) + , m_xBtnCancel(m_xBuilder->weld_button("cancel")) +{ + m_xBtnCancel->connect_clicked(LINK(this, WPFTEncodingDialog, CancelHdl)); + + insertEncodings(*m_xLbCharset); + m_xLbCharset->make_sorted(); + selectEncoding(*m_xLbCharset, encoding); + + m_xDialog->set_title(title); +} + +WPFTEncodingDialog::~WPFTEncodingDialog() {} + +OUString WPFTEncodingDialog::GetEncoding() const { return getEncoding(*m_xLbCharset); } + +IMPL_LINK_NOARG(WPFTEncodingDialog, CancelHdl, weld::Button&, void) +{ + m_userHasCancelled = true; + m_xDialog->response(RET_CANCEL); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/common/WPXSvInputStream.cxx b/writerperfect/source/common/WPXSvInputStream.cxx new file mode 100644 index 000000000..3364b0509 --- /dev/null +++ b/writerperfect/source/common/WPXSvInputStream.cxx @@ -0,0 +1,960 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <WPXSvInputStream.hxx> + +#include <com/sun/star/packages/zip/XZipFileAccess2.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <comphelper/processfactory.hxx> +#include <comphelper/seekableinput.hxx> +#include <o3tl/safeint.hxx> +#include <rtl/string.hxx> +#include <sal/log.hxx> + +#include <sot/storage.hxx> + +#include <tools/stream.hxx> +#include <unotools/streamwrap.hxx> +#include <unotools/ucbstreamhelper.hxx> + +#include <climits> +#include <limits> +#include <memory> +#include <string_view> +#include <unordered_map> +#include <vector> + +namespace writerperfect +{ +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; + +namespace container = com::sun::star::container; +namespace packages = com::sun::star::packages; + +namespace +{ +class PositionHolder +{ +public: + explicit PositionHolder(const Reference<XSeekable>& rxSeekable); + ~PositionHolder(); + PositionHolder(const PositionHolder&) = delete; + PositionHolder& operator=(const PositionHolder&) = delete; + +private: + const Reference<XSeekable> mxSeekable; + const sal_uInt64 mnPosition; +}; + +PositionHolder::PositionHolder(const Reference<XSeekable>& rxSeekable) + : mxSeekable(rxSeekable) + , mnPosition(rxSeekable->getPosition()) +{ +} + +PositionHolder::~PositionHolder() +{ + try + { + mxSeekable->seek(mnPosition); + } + catch (...) + { + } +} + +} // anonymous namespace + +namespace +{ +OUString lcl_normalizeSubStreamPath(const OUString& rPath) +{ + // accept paths which begin by '/' + // TODO: maybe this should do a full normalization + if (rPath.startsWith("/") && rPath.getLength() >= 2) + return rPath.copy(1); + return rPath; +} +} + +namespace +{ +OUString concatPath(std::u16string_view lhs, const OUString& rhs) +{ + if (lhs.empty()) + return rhs; + return OUString::Concat(lhs) + "/" + rhs; +} + +struct OLEStreamData +{ + OLEStreamData(const OString& rName, const OString& rvngName); + + tools::SvRef<SotStorageStream> stream; + + /** Name of the stream. + * + * This is not @c OUString, because we need to be able to + * produce const char* from it. + */ + OString name; + /** librevenge name of the stream. + * + * This is not @c OUString, because we need to be able to + * produce const char* from it. + */ + OString RVNGname; +}; + +typedef std::unordered_map<OUString, std::size_t> NameMap_t; +typedef std::unordered_map<OUString, tools::SvRef<SotStorage>> OLEStorageMap_t; + +/** Representation of an OLE2 storage. + * + * This class tries to bring a bit of sanity to use of SotStorage with + * respect to the needs of @c librevenge::RVNGInputStream API. It + * holds all nested storages for the whole lifetime (more precisely, + * since initialization, which is performed by calling @c + * initialize()), thus ensuring that no created stream is destroyed + * just because its parent storage went out of scope. It also holds a + * bidirectional map of stream names to their indexes (index of a + * stream is determined by deep-first traversal), which is also + * populated during initialization (member variables @c maStreams and + * @c maNameMap). + * + * Streams are created on demand (and saved, for the same reason as + * storages). + */ +struct OLEStorageImpl +{ + OLEStorageImpl(); + + void initialize(std::unique_ptr<SvStream> pStream); + + tools::SvRef<SotStorageStream> getStream(const OUString& rPath); + tools::SvRef<SotStorageStream> const& getStream(std::size_t nId); + +private: + void traverse(const tools::SvRef<SotStorage>& rStorage, std::u16string_view rPath); + + tools::SvRef<SotStorageStream> createStream(const OUString& rPath); + +public: + tools::SvRef<SotStorage> mxRootStorage; //< root storage of the OLE2 + OLEStorageMap_t maStorageMap; //< map of all sub storages by name + ::std::vector<OLEStreamData> maStreams; //< list of streams and their names + NameMap_t maNameMap; //< map of stream names to indexes (into @c maStreams) + bool mbInitialized; +}; + +OLEStreamData::OLEStreamData(const OString& rName, const OString& rvngName) + : name(rName) + , RVNGname(rvngName) +{ +} + +OLEStorageImpl::OLEStorageImpl() + : mbInitialized(false) +{ +} + +void OLEStorageImpl::initialize(std::unique_ptr<SvStream> pStream) +{ + if (!pStream) + return; + + mxRootStorage = new SotStorage(pStream.release(), true); + + traverse(mxRootStorage, u""); + + mbInitialized = true; +} + +tools::SvRef<SotStorageStream> OLEStorageImpl::getStream(const OUString& rPath) +{ + const OUString aPath(lcl_normalizeSubStreamPath(rPath)); + NameMap_t::iterator aIt = maNameMap.find(aPath); + + // For the while don't return stream in this situation. + // Later, given how libcdr's zip stream implementation behaves, + // return the first stream in the storage if there is one. + if (maNameMap.end() == aIt) + return tools::SvRef<SotStorageStream>(); + + if (!maStreams[aIt->second].stream.is()) + maStreams[aIt->second].stream + = createStream(OStringToOUString(maStreams[aIt->second].name, RTL_TEXTENCODING_UTF8)); + + return maStreams[aIt->second].stream; +} + +tools::SvRef<SotStorageStream> const& OLEStorageImpl::getStream(const std::size_t nId) +{ + if (!maStreams[nId].stream.is()) + maStreams[nId].stream + = createStream(OStringToOUString(maStreams[nId].name, RTL_TEXTENCODING_UTF8)); + + return maStreams[nId].stream; +} + +void OLEStorageImpl::traverse(const tools::SvRef<SotStorage>& rStorage, std::u16string_view rPath) +{ + SvStorageInfoList infos; + + rStorage->FillInfoList(&infos); + + for (const auto& info : infos) + { + if (info.IsStream()) + { + OUString baseName = info.GetName(), rvngName = baseName; + // librevenge::RVNGOLEStream ignores the first character when is a control code, so ... + if (!rvngName.isEmpty() && rvngName.toChar() < 32) + rvngName = rvngName.copy(1); + maStreams.emplace_back( + OUStringToOString(concatPath(rPath, baseName), RTL_TEXTENCODING_UTF8), + OUStringToOString(concatPath(rPath, rvngName), RTL_TEXTENCODING_UTF8)); + maNameMap[concatPath(rPath, rvngName)] = maStreams.size() - 1; + } + else if (info.IsStorage()) + { + const OUString aPath = concatPath(rPath, info.GetName()); + tools::SvRef<SotStorage> aStorage + = rStorage->OpenSotStorage(info.GetName(), StreamMode::STD_READ); + maStorageMap[aPath] = aStorage; + + // deep-first traversal + traverse(aStorage, aPath); + } + else + { + SAL_WARN("writerperfect", + "OLEStorageImpl::traverse: invalid storage entry, neither stream nor file"); + } + } +} + +tools::SvRef<SotStorageStream> OLEStorageImpl::createStream(const OUString& rPath) +{ + const sal_Int32 nDelim = rPath.lastIndexOf(u'/'); + + if (-1 == nDelim) + return mxRootStorage->OpenSotStream(rPath, StreamMode::STD_READ); + + const OUString aDir = rPath.copy(0, nDelim); + const OUString aName = rPath.copy(nDelim + 1); + + const OLEStorageMap_t::const_iterator aIt = maStorageMap.find(aDir); + + if (maStorageMap.end() == aIt) + return nullptr; + + return aIt->second->OpenSotStream(aName, StreamMode::STD_READ); +} +} + +namespace +{ +struct ZipStreamData +{ + explicit ZipStreamData(const OString& rName); + + Reference<XInputStream> xStream; + + /** Name of the stream. + * + * This is not @c OUString, because we need to be able to + * produce const char* from it. + */ + OString aName; +}; + +/** Representation of a Zip storage. + * + * This is quite similar to OLEStorageImpl, except that we do not need + * to keep all storages (folders) open. + */ +struct ZipStorageImpl +{ + explicit ZipStorageImpl(const Reference<container::XNameAccess>& rxContainer); + + /** Initialize for access. + * + * This creates a bidirectional map of stream names to their + * indexes (index of a stream is determined by deep-first + * traversal). + */ + void initialize(); + + Reference<XInputStream> getStream(const OUString& rPath); + Reference<XInputStream> const& getStream(std::size_t nId); + +private: + void traverse(const Reference<container::XNameAccess>& rxEnum); + + Reference<XInputStream> createStream(const OUString& rPath); + +public: + Reference<container::XNameAccess> mxContainer; //< root of the Zip + ::std::vector<ZipStreamData> maStreams; //< list of streams and their names + NameMap_t maNameMap; //< map of stream names to indexes (into @c maStreams) + bool mbInitialized; +}; + +ZipStreamData::ZipStreamData(const OString& rName) + : aName(rName) +{ +} + +ZipStorageImpl::ZipStorageImpl(const Reference<container::XNameAccess>& rxContainer) + : mxContainer(rxContainer) + , mbInitialized(false) +{ + assert(mxContainer.is()); +} + +void ZipStorageImpl::initialize() +{ + traverse(mxContainer); + + mbInitialized = true; +} + +Reference<XInputStream> ZipStorageImpl::getStream(const OUString& rPath) +{ + const OUString aPath(lcl_normalizeSubStreamPath(rPath)); + NameMap_t::iterator aIt = maNameMap.find(aPath); + + // For the while don't return stream in this situation. + // Later, given how libcdr's zip stream implementation behaves, + // return the first stream in the storage if there is one. + if (maNameMap.end() == aIt) + return Reference<XInputStream>(); + + if (!maStreams[aIt->second].xStream.is()) + maStreams[aIt->second].xStream = createStream(aPath); + + return maStreams[aIt->second].xStream; +} + +Reference<XInputStream> const& ZipStorageImpl::getStream(const std::size_t nId) +{ + if (!maStreams[nId].xStream.is()) + maStreams[nId].xStream + = createStream(OStringToOUString(maStreams[nId].aName, RTL_TEXTENCODING_UTF8)); + + return maStreams[nId].xStream; +} + +void ZipStorageImpl::traverse(const Reference<container::XNameAccess>& rxContainer) +{ + const Sequence<OUString> lNames = rxContainer->getElementNames(); + + maStreams.reserve(lNames.getLength()); + + for (const auto& rName : lNames) + { + if (!rName.endsWith("/")) // skip dirs + { + maStreams.emplace_back(OUStringToOString(rName, RTL_TEXTENCODING_UTF8)); + maNameMap[rName] = maStreams.size() - 1; + } + } +} + +Reference<XInputStream> ZipStorageImpl::createStream(const OUString& rPath) +{ + Reference<XInputStream> xStream; + + try + { + const Reference<XInputStream> xInputStream(mxContainer->getByName(rPath), UNO_QUERY_THROW); + const Reference<XSeekable> xSeekable(xInputStream, UNO_QUERY); + + if (xSeekable.is()) + xStream = xInputStream; + else + xStream.set(new comphelper::OSeekableInputWrapper( + xInputStream, comphelper::getProcessComponentContext())); + } + catch (const Exception&) + { + // nothing needed + } + + return xStream; +} +} + +class WPXSvInputStreamImpl +{ +public: + explicit WPXSvInputStreamImpl(css::uno::Reference<css::io::XInputStream> const& xStream); + + bool isStructured(); + unsigned subStreamCount(); + const char* subStreamName(unsigned id); + bool existsSubStream(const char* name); + librevenge::RVNGInputStream* getSubStreamByName(const char* name); + librevenge::RVNGInputStream* getSubStreamById(unsigned id); + + const unsigned char* read(unsigned long numBytes, unsigned long& numBytesRead); + int seek(tools::Long offset); + tools::Long tell(); + bool isEnd(); + + void invalidateReadBuffer(); + +private: + bool isOLE(); + void ensureOLEIsInitialized(); + + bool isZip(); + void ensureZipIsInitialized(); + + static librevenge::RVNGInputStream* + createWPXStream(const tools::SvRef<SotStorageStream>& rxStorage); + static librevenge::RVNGInputStream* createWPXStream(const Reference<XInputStream>& rxStream); + +private: + css::uno::Reference<css::io::XInputStream> mxStream; + css::uno::Reference<css::io::XSeekable> mxSeekable; + css::uno::Sequence<sal_Int8> maData; + std::unique_ptr<OLEStorageImpl> mpOLEStorage; + std::unique_ptr<ZipStorageImpl> mpZipStorage; + bool mbCheckedOLE; + bool mbCheckedZip; + +public: + sal_Int64 mnLength; + const unsigned char* mpReadBuffer; + unsigned long mnReadBufferLength; + unsigned long mnReadBufferPos; +}; + +WPXSvInputStreamImpl::WPXSvInputStreamImpl(Reference<XInputStream> const& xStream) + : mxStream(xStream) + , mxSeekable(xStream, UNO_QUERY) + , maData(0) + , mbCheckedOLE(false) + , mbCheckedZip(false) + , mnLength(0) + , mpReadBuffer(nullptr) + , mnReadBufferLength(0) + , mnReadBufferPos(0) +{ + if (!xStream.is() || !mxStream.is()) + mnLength = 0; + else + { + if (!mxSeekable.is()) + mnLength = 0; + else + { + try + { + mnLength = mxSeekable->getLength(); + if (0 < mxSeekable->getPosition()) + mxSeekable->seek(0); + } + catch (...) + { + SAL_WARN("writerperfect", "mnLength = mxSeekable->getLength() threw exception"); + mnLength = 0; + } + } + } +} + +const unsigned char* WPXSvInputStreamImpl::read(unsigned long numBytes, unsigned long& numBytesRead) +{ + numBytesRead = 0; + + if (numBytes == 0 || isEnd()) + return nullptr; + + numBytesRead = mxStream->readSomeBytes(maData, numBytes); + if (numBytesRead == 0) + return nullptr; + + return reinterpret_cast<const unsigned char*>(maData.getConstArray()); +} + +tools::Long WPXSvInputStreamImpl::tell() +{ + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return -1; + else + { + const sal_Int64 tmpPosition = mxSeekable->getPosition(); + if ((tmpPosition < 0) || (tmpPosition > LONG_MAX)) + return -1; + return static_cast<tools::Long>(tmpPosition); + } +} + +int WPXSvInputStreamImpl::seek(tools::Long offset) +{ + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return -1; + + const sal_Int64 tmpPosition = mxSeekable->getPosition(); + if ((tmpPosition < 0) || (tmpPosition > LONG_MAX)) + return -1; + + try + { + mxSeekable->seek(offset); + return 0; + } + catch (...) + { + SAL_WARN("writerperfect", "mxSeekable->seek(offset) threw exception"); + return -1; + } +} + +bool WPXSvInputStreamImpl::isEnd() +{ + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return true; + return (mxSeekable->getPosition() >= mnLength); +} + +bool WPXSvInputStreamImpl::isStructured() +{ + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return false; + + PositionHolder pos(mxSeekable); + mxSeekable->seek(0); + + if (isOLE()) + return true; + + mxSeekable->seek(0); + + return isZip(); +} + +unsigned WPXSvInputStreamImpl::subStreamCount() +{ + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return 0; + + PositionHolder pos(mxSeekable); + mxSeekable->seek(0); + + if (isOLE()) + { + ensureOLEIsInitialized(); + + return mpOLEStorage->maStreams.size(); + } + + mxSeekable->seek(0); + + if (isZip()) + { + ensureZipIsInitialized(); + + return mpZipStorage->maStreams.size(); + } + + return 0; +} + +const char* WPXSvInputStreamImpl::subStreamName(const unsigned id) +{ + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return nullptr; + + PositionHolder pos(mxSeekable); + mxSeekable->seek(0); + + if (isOLE()) + { + ensureOLEIsInitialized(); + + if (mpOLEStorage->maStreams.size() <= id) + return nullptr; + + return mpOLEStorage->maStreams[id].RVNGname.getStr(); + } + + mxSeekable->seek(0); + + if (isZip()) + { + ensureZipIsInitialized(); + + if (mpZipStorage->maStreams.size() <= id) + return nullptr; + + return mpZipStorage->maStreams[id].aName.getStr(); + } + + return nullptr; +} + +bool WPXSvInputStreamImpl::existsSubStream(const char* const name) +{ + if (!name) + return false; + + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return false; + + PositionHolder pos(mxSeekable); + mxSeekable->seek(0); + + const OUString aName(OStringToOUString(std::string_view(name), RTL_TEXTENCODING_UTF8)); + + if (isOLE()) + { + ensureOLEIsInitialized(); + return mpOLEStorage->maNameMap.end() != mpOLEStorage->maNameMap.find(aName); + } + + mxSeekable->seek(0); + + if (isZip()) + { + ensureZipIsInitialized(); + return mpZipStorage->maNameMap.end() != mpZipStorage->maNameMap.find(aName); + } + + return false; +} + +librevenge::RVNGInputStream* WPXSvInputStreamImpl::getSubStreamByName(const char* const name) +{ + if (!name) + return nullptr; + + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return nullptr; + + PositionHolder pos(mxSeekable); + mxSeekable->seek(0); + + const OUString aName(OStringToOUString(std::string_view(name), RTL_TEXTENCODING_UTF8)); + + if (isOLE()) + { + ensureOLEIsInitialized(); + return createWPXStream(mpOLEStorage->getStream(aName)); + } + + mxSeekable->seek(0); + + if (isZip()) + { + ensureZipIsInitialized(); + + try + { + return createWPXStream(mpZipStorage->getStream(aName)); + } + catch (const Exception&) + { + // nothing needed + } + } + + return nullptr; +} + +librevenge::RVNGInputStream* WPXSvInputStreamImpl::getSubStreamById(const unsigned id) +{ + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return nullptr; + + PositionHolder pos(mxSeekable); + mxSeekable->seek(0); + + if (isOLE()) + { + ensureOLEIsInitialized(); + + if (mpOLEStorage->maStreams.size() <= id) + return nullptr; + + return createWPXStream(mpOLEStorage->getStream(id)); + } + + mxSeekable->seek(0); + + if (isZip()) + { + ensureZipIsInitialized(); + + if (mpZipStorage->maStreams.size() <= id) + return nullptr; + + try + { + return createWPXStream(mpZipStorage->getStream(id)); + } + catch (const Exception&) + { + // nothing needed + } + } + return nullptr; +} + +void WPXSvInputStreamImpl::invalidateReadBuffer() +{ + if (mpReadBuffer) + { + seek(tell() + static_cast<tools::Long>(mnReadBufferPos) + - static_cast<tools::Long>(mnReadBufferLength)); + mpReadBuffer = nullptr; + mnReadBufferPos = 0; + mnReadBufferLength = 0; + } +} + +librevenge::RVNGInputStream* +WPXSvInputStreamImpl::createWPXStream(const tools::SvRef<SotStorageStream>& rxStorage) +{ + if (rxStorage.is()) + { + Reference<XInputStream> xContents(new utl::OSeekableInputStreamWrapper(rxStorage.get())); + return new WPXSvInputStream(xContents); + } + return nullptr; +} + +librevenge::RVNGInputStream* +WPXSvInputStreamImpl::createWPXStream(const Reference<XInputStream>& rxStream) +{ + if (rxStream.is()) + return new WPXSvInputStream(rxStream); + else + return nullptr; +} + +bool WPXSvInputStreamImpl::isOLE() +{ + if (!mbCheckedOLE) + { + assert(0 == mxSeekable->getPosition()); + + std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(mxStream)); + if (pStream && SotStorage::IsOLEStorage(pStream.get())) + mpOLEStorage.reset(new OLEStorageImpl()); + + mbCheckedOLE = true; + } + + return bool(mpOLEStorage); +} + +bool WPXSvInputStreamImpl::isZip() +{ + if (!mbCheckedZip) + { + assert(0 == mxSeekable->getPosition()); + + try + { + const Reference<XComponentContext> xContext(comphelper::getProcessComponentContext(), + UNO_SET_THROW); + const Reference<packages::zip::XZipFileAccess2> xZip( + xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.packages.zip.ZipFileAccess", { Any(mxStream) }, xContext), + UNO_QUERY_THROW); + mpZipStorage.reset(new ZipStorageImpl(xZip)); + } + catch (const Exception&) + { + // ignore + } + + mbCheckedZip = true; + } + + return bool(mpZipStorage); +} + +void WPXSvInputStreamImpl::ensureOLEIsInitialized() +{ + assert(mpOLEStorage); + + if (!mpOLEStorage->mbInitialized) + mpOLEStorage->initialize(utl::UcbStreamHelper::CreateStream(mxStream)); +} + +void WPXSvInputStreamImpl::ensureZipIsInitialized() +{ + assert(mpZipStorage); + + if (!mpZipStorage->mbInitialized) + mpZipStorage->initialize(); +} + +WPXSvInputStream::WPXSvInputStream(Reference<XInputStream> const& xStream) + : mpImpl(new WPXSvInputStreamImpl(xStream)) +{ +} + +WPXSvInputStream::~WPXSvInputStream() {} + +#define BUFFER_MAX 65536 + +const unsigned char* WPXSvInputStream::read(unsigned long numBytes, unsigned long& numBytesRead) +{ + numBytesRead = 0; + + if (numBytes == 0 || numBytes > std::numeric_limits<unsigned long>::max() / 2) + return nullptr; + + if (mpImpl->mpReadBuffer) + { + if ((mpImpl->mnReadBufferPos + numBytes > mpImpl->mnReadBufferPos) + && (mpImpl->mnReadBufferPos + numBytes <= mpImpl->mnReadBufferLength)) + { + const unsigned char* pTmp = mpImpl->mpReadBuffer + mpImpl->mnReadBufferPos; + mpImpl->mnReadBufferPos += numBytes; + numBytesRead = numBytes; + return pTmp; + } + + mpImpl->invalidateReadBuffer(); + } + + unsigned long curpos = static_cast<unsigned long>(mpImpl->tell()); + if (curpos == static_cast<unsigned long>(-1)) // returned ERROR + return nullptr; + + if ((curpos + numBytes < curpos) /*overflow*/ + || (curpos + numBytes + >= o3tl::make_unsigned(mpImpl->mnLength))) /*reading more than available*/ + { + numBytes = mpImpl->mnLength - curpos; + } + + if (numBytes < BUFFER_MAX) + { + if (BUFFER_MAX < mpImpl->mnLength - curpos) + mpImpl->mnReadBufferLength = BUFFER_MAX; + else /* BUFFER_MAX >= mpImpl->mnLength - curpos */ + mpImpl->mnReadBufferLength = mpImpl->mnLength - curpos; + } + else + mpImpl->mnReadBufferLength = numBytes; + + unsigned long tmpNumBytes(0); + mpImpl->mpReadBuffer = mpImpl->read(mpImpl->mnReadBufferLength, tmpNumBytes); + if (tmpNumBytes != mpImpl->mnReadBufferLength) + mpImpl->mnReadBufferLength = tmpNumBytes; + + mpImpl->mnReadBufferPos = 0; + if (!mpImpl->mnReadBufferLength) + return nullptr; + + if (numBytes <= mpImpl->mnReadBufferLength) + numBytesRead = numBytes; + else + numBytesRead = mpImpl->mnReadBufferLength; + + mpImpl->mnReadBufferPos += numBytesRead; + return mpImpl->mpReadBuffer; +} + +long WPXSvInputStream::tell() +{ + tools::Long retVal = mpImpl->tell(); + return retVal - static_cast<tools::Long>(mpImpl->mnReadBufferLength) + + static_cast<tools::Long>(mpImpl->mnReadBufferPos); +} + +int WPXSvInputStream::seek(long offset, librevenge::RVNG_SEEK_TYPE seekType) +{ + sal_Int64 tmpOffset = offset; + if (seekType == librevenge::RVNG_SEEK_CUR) + tmpOffset += tell(); + if (seekType == librevenge::RVNG_SEEK_END) + tmpOffset += mpImpl->mnLength; + + int retVal = 0; + if (tmpOffset < 0) + { + tmpOffset = 0; + retVal = -1; + } + if (tmpOffset > mpImpl->mnLength) + { + tmpOffset = mpImpl->mnLength; + retVal = -1; + } + + if (tmpOffset < mpImpl->tell() + && o3tl::make_unsigned(tmpOffset) + >= static_cast<unsigned long>(mpImpl->tell()) - mpImpl->mnReadBufferLength) + { + mpImpl->mnReadBufferPos = static_cast<unsigned long>( + tmpOffset + static_cast<tools::Long>(mpImpl->mnReadBufferLength) - mpImpl->tell()); + return retVal; + } + + mpImpl->invalidateReadBuffer(); + + if (mpImpl->seek(tmpOffset)) + return -1; + return retVal; +} + +bool WPXSvInputStream::isEnd() +{ + return mpImpl->isEnd() && mpImpl->mnReadBufferPos == mpImpl->mnReadBufferLength; +} + +bool WPXSvInputStream::isStructured() +{ + mpImpl->invalidateReadBuffer(); + return mpImpl->isStructured(); +} + +unsigned WPXSvInputStream::subStreamCount() +{ + mpImpl->invalidateReadBuffer(); + return mpImpl->subStreamCount(); +} + +const char* WPXSvInputStream::subStreamName(const unsigned id) +{ + mpImpl->invalidateReadBuffer(); + return mpImpl->subStreamName(id); +} + +bool WPXSvInputStream::existsSubStream(const char* const name) +{ + mpImpl->invalidateReadBuffer(); + return mpImpl->existsSubStream(name); +} + +librevenge::RVNGInputStream* WPXSvInputStream::getSubStreamByName(const char* name) +{ + mpImpl->invalidateReadBuffer(); + return mpImpl->getSubStreamByName(name); +} + +librevenge::RVNGInputStream* WPXSvInputStream::getSubStreamById(const unsigned id) +{ + mpImpl->invalidateReadBuffer(); + return mpImpl->getSubStreamById(id); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/CDRImportFilter.cxx b/writerperfect/source/draw/CDRImportFilter.cxx new file mode 100644 index 000000000..34b490326 --- /dev/null +++ b/writerperfect/source/draw/CDRImportFilter.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* CDRImportFilter: Sets up the filter, and calls OdgExporter + * to do the actual filtering + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* "This product is not manufactured, approved, or supported by + * Corel Corporation or Corel Corporation Limited." + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libcdr/libcdr.h> + +#include "CDRImportFilter.hxx" + +bool CDRImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) +{ + return libcdr::CDRDocument::parse(&rInput, &rGenerator); +} + +bool CDRImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + if (libcdr::CDRDocument::isSupported(&rInput)) + { + rTypeName = "draw_CorelDraw_Document"; + return true; + } + + return false; +} + +// XServiceInfo +OUString SAL_CALL CDRImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Draw.CDRImportFilter"; +} + +sal_Bool SAL_CALL CDRImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL CDRImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Draw_CDRImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new CDRImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/CDRImportFilter.hxx b/writerperfect/source/draw/CDRImportFilter.hxx new file mode 100644 index 000000000..0e8247131 --- /dev/null +++ b/writerperfect/source/draw/CDRImportFilter.hxx @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* "This product is not manufactured, approved, or supported by + * Corel Corporation or Corel Corporation Limited." + */ +#pragma once + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdg.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class CDRImportFilter : public writerperfect::ImportFilter<OdgGenerator> +{ +public: + explicit CDRImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdgGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/CMXImportFilter.cxx b/writerperfect/source/draw/CMXImportFilter.cxx new file mode 100644 index 000000000..23aab816a --- /dev/null +++ b/writerperfect/source/draw/CMXImportFilter.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* CMXImportFilter: Sets up the filter, and calls OdgExporter + * to do the actual filtering + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* "This product is not manufactured, approved, or supported by + * Corel Corporation or Corel Corporation Limited." + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libcdr/libcdr.h> + +#include "CMXImportFilter.hxx" + +bool CMXImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) +{ + return libcdr::CMXDocument::parse(&rInput, &rGenerator); +} + +bool CMXImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + if (libcdr::CMXDocument::isSupported(&rInput)) + { + rTypeName = "draw_Corel_Presentation_Exchange"; + return true; + } + + return false; +} + +// XServiceInfo +OUString SAL_CALL CMXImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Draw.CMXImportFilter"; +} + +sal_Bool SAL_CALL CMXImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL CMXImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Draw_CMXImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new CMXImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/CMXImportFilter.hxx b/writerperfect/source/draw/CMXImportFilter.hxx new file mode 100644 index 000000000..cc3b19428 --- /dev/null +++ b/writerperfect/source/draw/CMXImportFilter.hxx @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* "This product is not manufactured, approved, or supported by + * Corel Corporation or Corel Corporation Limited." + */ +#pragma once + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdg.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class CMXImportFilter : public writerperfect::ImportFilter<OdgGenerator> +{ +public: + explicit CMXImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdgGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/FreehandImportFilter.cxx b/writerperfect/source/draw/FreehandImportFilter.cxx new file mode 100644 index 000000000..68dd7b56b --- /dev/null +++ b/writerperfect/source/draw/FreehandImportFilter.cxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* FreehandImportFilter: Sets up the filter, and calls OdgExporter + * to do the actual filtering + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libfreehand/libfreehand.h> + +#include "FreehandImportFilter.hxx" + +bool FreehandImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) +{ + return libfreehand::FreeHandDocument::parse(&rInput, &rGenerator); +} + +bool FreehandImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + if (libfreehand::FreeHandDocument::isSupported(&rInput)) + { + rTypeName = "draw_Freehand_Document"; + return true; + } + + return false; +} + +// XServiceInfo +OUString SAL_CALL FreehandImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Draw.FreehandImportFilter"; +} + +sal_Bool SAL_CALL FreehandImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL FreehandImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Draw_FreehandImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new FreehandImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/FreehandImportFilter.hxx b/writerperfect/source/draw/FreehandImportFilter.hxx new file mode 100644 index 000000000..083218117 --- /dev/null +++ b/writerperfect/source/draw/FreehandImportFilter.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdg.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class FreehandImportFilter : public writerperfect::ImportFilter<OdgGenerator> +{ +public: + explicit FreehandImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdgGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/MSPUBImportFilter.cxx b/writerperfect/source/draw/MSPUBImportFilter.cxx new file mode 100644 index 000000000..ba34cd2f1 --- /dev/null +++ b/writerperfect/source/draw/MSPUBImportFilter.cxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* MSPUBImportFilter: Sets up the filter, and calls OdgExporter + * to do the actual filtering + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libmspub/libmspub.h> + +#include "MSPUBImportFilter.hxx" + +bool MSPUBImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) +{ + return libmspub::MSPUBDocument::parse(&rInput, &rGenerator); +} + +bool MSPUBImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + if (libmspub::MSPUBDocument::isSupported(&rInput)) + { + rTypeName = "draw_Publisher_Document"; + return true; + } + + return false; +} + +// XServiceInfo +OUString SAL_CALL MSPUBImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Draw.MSPUBImportFilter"; +} + +sal_Bool SAL_CALL MSPUBImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL MSPUBImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Draw_MSPUBImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new MSPUBImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/MSPUBImportFilter.hxx b/writerperfect/source/draw/MSPUBImportFilter.hxx new file mode 100644 index 000000000..a84302703 --- /dev/null +++ b/writerperfect/source/draw/MSPUBImportFilter.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdg.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class MSPUBImportFilter : public writerperfect::ImportFilter<OdgGenerator> +{ +public: + explicit MSPUBImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdgGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/MWAWDrawImportFilter.cxx b/writerperfect/source/draw/MWAWDrawImportFilter.cxx new file mode 100644 index 000000000..000debdcb --- /dev/null +++ b/writerperfect/source/draw/MWAWDrawImportFilter.cxx @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* MWAWDrawImportFilter: Sets up the filter, and calls DocumentCollector + * to do the actual filtering + * + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libmwaw/libmwaw.hxx> + +#include "MWAWDrawImportFilter.hxx" + +static bool handleEmbeddedMWAWGraphicObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdgGenerator exporter; + exporter.addDocumentHandler(pHandler, streamType); + return MWAWDocument::decodeGraphic(data, &exporter); +} + +static bool handleEmbeddedMWAWSpreadsheetObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdsGenerator exporter; + exporter.registerEmbeddedObjectHandler("image/mwaw-odg", &handleEmbeddedMWAWGraphicObject); + exporter.addDocumentHandler(pHandler, streamType); + return MWAWDocument::decodeSpreadsheet(data, &exporter); +} + +bool MWAWDrawImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) +{ + return MWAWDocument::MWAW_R_OK == MWAWDocument::parse(&rInput, &rGenerator); +} + +bool MWAWDrawImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + rTypeName.clear(); + + MWAWDocument::Type docType = MWAWDocument::MWAW_T_UNKNOWN; + MWAWDocument::Kind docKind = MWAWDocument::MWAW_K_UNKNOWN; + const MWAWDocument::Confidence confidence + = MWAWDocument::isFileFormatSupported(&rInput, docType, docKind); + + if (confidence == MWAWDocument::MWAW_C_EXCELLENT) + { + switch (docKind) + { + case MWAWDocument::MWAW_K_DRAW: + switch (docType) + { + case MWAWDocument::MWAW_T_CLARISWORKS: + rTypeName = "draw_ClarisWorks"; + break; + default: + rTypeName = "MWAW_Drawing"; + break; + } + break; + case MWAWDocument::MWAW_K_PAINT: + switch (docType) + { + case MWAWDocument::MWAW_T_CLARISWORKS: + rTypeName = "draw_ClarisWorks"; + break; + default: + rTypeName = "MWAW_Bitmap"; + break; + } + break; + default: + break; + } + } + + return !rTypeName.isEmpty(); +} + +void MWAWDrawImportFilter::doRegisterHandlers(OdgGenerator& rGenerator) +{ + rGenerator.registerEmbeddedObjectHandler("image/mwaw-odg", &handleEmbeddedMWAWGraphicObject); + rGenerator.registerEmbeddedObjectHandler("image/mwaw-ods", + &handleEmbeddedMWAWSpreadsheetObject); +} + +// XServiceInfo +OUString SAL_CALL MWAWDrawImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Draw.MWAWDrawImportFilter"; +} + +sal_Bool SAL_CALL MWAWDrawImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL MWAWDrawImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Draw_MWAWDrawImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new MWAWDrawImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/MWAWDrawImportFilter.hxx b/writerperfect/source/draw/MWAWDrawImportFilter.hxx new file mode 100644 index 000000000..ed0571dad --- /dev/null +++ b/writerperfect/source/draw/MWAWDrawImportFilter.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdg.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class MWAWDrawImportFilter : public writerperfect::ImportFilter<OdgGenerator> +{ +public: + explicit MWAWDrawImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdgGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) override; + virtual void doRegisterHandlers(OdgGenerator& rGenerator) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/PageMakerImportFilter.cxx b/writerperfect/source/draw/PageMakerImportFilter.cxx new file mode 100644 index 000000000..5f5379de9 --- /dev/null +++ b/writerperfect/source/draw/PageMakerImportFilter.cxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* PageMakerImportFilter: Sets up the filter, and calls OdgExporter + * to do the actual filtering + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <libpagemaker/libpagemaker.h> + +#include <cppuhelper/supportsservice.hxx> + +#include "PageMakerImportFilter.hxx" + +bool PageMakerImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) +{ + return libpagemaker::PMDocument::parse(&rInput, &rGenerator); +} + +bool PageMakerImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + if (libpagemaker::PMDocument::isSupported(&rInput)) + { + rTypeName = "draw_PageMaker_Document"; + return true; + } + + return false; +} + +// XServiceInfo +OUString SAL_CALL PageMakerImportFilter::getImplementationName() +{ + return "org.libreoffice.comp.Draw.PageMakerImportFilter"; +} + +sal_Bool SAL_CALL PageMakerImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL PageMakerImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_Draw_PageMakerImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new PageMakerImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/PageMakerImportFilter.hxx b/writerperfect/source/draw/PageMakerImportFilter.hxx new file mode 100644 index 000000000..b98213a27 --- /dev/null +++ b/writerperfect/source/draw/PageMakerImportFilter.hxx @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdg.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class PageMakerImportFilter : public writerperfect::ImportFilter<OdgGenerator> +{ +public: + explicit PageMakerImportFilter( + const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdgGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/QXPImportFilter.cxx b/writerperfect/source/draw/QXPImportFilter.cxx new file mode 100644 index 000000000..c644ad470 --- /dev/null +++ b/writerperfect/source/draw/QXPImportFilter.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* QXPImportFilter: Sets up the filter, and calls OdgExporter + * to do the actual filtering + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <libqxp/libqxp.h> + +#include <cppuhelper/supportsservice.hxx> + +#include "QXPImportFilter.hxx" + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::XInterface; + +bool QXPImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) +{ + return libqxp::QXPDocument::parse(&rInput, &rGenerator) == libqxp::QXPDocument::RESULT_OK; +} + +bool QXPImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + if (libqxp::QXPDocument::isSupported(&rInput)) + { + rTypeName = "draw_QXP_Document"; + return true; + } + + return false; +} + +// XServiceInfo +OUString SAL_CALL QXPImportFilter::getImplementationName() +{ + return "org.libreoffice.comp.Draw.QXPImportFilter"; +} + +sal_Bool SAL_CALL QXPImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence<OUString> SAL_CALL QXPImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_Draw_QXPImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new QXPImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/QXPImportFilter.hxx b/writerperfect/source/draw/QXPImportFilter.hxx new file mode 100644 index 000000000..5854125d6 --- /dev/null +++ b/writerperfect/source/draw/QXPImportFilter.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdg.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class QXPImportFilter : public writerperfect::ImportFilter<OdgGenerator> +{ +public: + explicit QXPImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdgGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/StarOfficeDrawImportFilter.cxx b/writerperfect/source/draw/StarOfficeDrawImportFilter.cxx new file mode 100644 index 000000000..1c335bfc4 --- /dev/null +++ b/writerperfect/source/draw/StarOfficeDrawImportFilter.cxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libstaroffice/libstaroffice.hxx> + +#include "StarOfficeDrawImportFilter.hxx" + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::XInterface; + +static bool handleEmbeddedSTOFFGraphicObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdgGenerator exporter; + exporter.addDocumentHandler(pHandler, streamType); + return STOFFDocument::decodeGraphic(data, &exporter); +} + +static bool handleEmbeddedSTOFFSpreadsheetObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdsGenerator exporter; + exporter.registerEmbeddedObjectHandler("image/stoff-odg", &handleEmbeddedSTOFFGraphicObject); + exporter.addDocumentHandler(pHandler, streamType); + return STOFFDocument::decodeSpreadsheet(data, &exporter); +} + +bool StarOfficeDrawImportFilter::doImportDocument(weld::Window*, + librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) +{ + return STOFFDocument::STOFF_R_OK == STOFFDocument::parse(&rInput, &rGenerator); +} + +bool StarOfficeDrawImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, + OUString& rTypeName) +{ + rTypeName.clear(); + + STOFFDocument::Kind docKind = STOFFDocument::STOFF_K_UNKNOWN; + const STOFFDocument::Confidence confidence + = STOFFDocument::isFileFormatSupported(&rInput, docKind); + + if (confidence == STOFFDocument::STOFF_C_EXCELLENT + || confidence == STOFFDocument::STOFF_C_SUPPORTED_ENCRYPTION) + { + switch (docKind) + { + case STOFFDocument::STOFF_K_DRAW: + rTypeName = "StarOffice_Drawing"; + break; + default: + break; + } + } + + return !rTypeName.isEmpty(); +} + +void StarOfficeDrawImportFilter::doRegisterHandlers(OdgGenerator& rGenerator) +{ + rGenerator.registerEmbeddedObjectHandler("image/stoff-odg", &handleEmbeddedSTOFFGraphicObject); + rGenerator.registerEmbeddedObjectHandler("image/stoff-ods", + &handleEmbeddedSTOFFSpreadsheetObject); +} + +// XServiceInfo +OUString SAL_CALL StarOfficeDrawImportFilter::getImplementationName() +{ + return "org.libreoffice.comp.Draw.StarOfficeDrawImportFilter"; +} + +sal_Bool SAL_CALL StarOfficeDrawImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence<OUString> SAL_CALL StarOfficeDrawImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_Draw_StarOfficeDrawImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new StarOfficeDrawImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/StarOfficeDrawImportFilter.hxx b/writerperfect/source/draw/StarOfficeDrawImportFilter.hxx new file mode 100644 index 000000000..ca44ceb48 --- /dev/null +++ b/writerperfect/source/draw/StarOfficeDrawImportFilter.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdg.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class StarOfficeDrawImportFilter : public writerperfect::ImportFilter<OdgGenerator> +{ +public: + explicit StarOfficeDrawImportFilter( + const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdgGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) override; + virtual void doRegisterHandlers(OdgGenerator& rGenerator) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/VisioImportFilter.cxx b/writerperfect/source/draw/VisioImportFilter.cxx new file mode 100644 index 000000000..33b23aae4 --- /dev/null +++ b/writerperfect/source/draw/VisioImportFilter.cxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* VisioImportFilter: Sets up the filter, and calls OdgExporter + * to do the actual filtering + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libvisio/libvisio.h> + +#include "VisioImportFilter.hxx" + +bool VisioImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) +{ + return libvisio::VisioDocument::parse(&rInput, &rGenerator); +} + +bool VisioImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + if (libvisio::VisioDocument::isSupported(&rInput)) + { + rTypeName = "draw_Visio_Document"; + return true; + } + + return false; +} + +// XServiceInfo +OUString SAL_CALL VisioImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Draw.VisioImportFilter"; +} + +sal_Bool SAL_CALL VisioImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL VisioImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Draw_VisioImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new VisioImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/VisioImportFilter.hxx b/writerperfect/source/draw/VisioImportFilter.hxx new file mode 100644 index 000000000..9d0e8cadb --- /dev/null +++ b/writerperfect/source/draw/VisioImportFilter.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdg.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class VisioImportFilter : public writerperfect::ImportFilter<OdgGenerator> +{ +public: + explicit VisioImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdgGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/WPGImportFilter.cxx b/writerperfect/source/draw/WPGImportFilter.cxx new file mode 100644 index 000000000..10411ea3b --- /dev/null +++ b/writerperfect/source/draw/WPGImportFilter.cxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* WPGImportFilter: Sets up the filter, and calls OdgExporter + * to do the actual filtering + * + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* "This product is not manufactured, approved, or supported by + * Corel Corporation or Corel Corporation Limited." + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libwpg/libwpg.h> + +#include "WPGImportFilter.hxx" + +bool WPGImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) +{ + return libwpg::WPGraphics::parse(&rInput, &rGenerator); +} + +bool WPGImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + if (libwpg::WPGraphics::isSupported(&rInput)) + { + rTypeName = "draw_WordPerfect_Graphics"; + return true; + } + + return false; +} + +// XServiceInfo +OUString SAL_CALL WPGImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Draw.WPGImportFilter"; +} + +sal_Bool SAL_CALL WPGImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL WPGImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Draw_WPGImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new WPGImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/WPGImportFilter.hxx b/writerperfect/source/draw/WPGImportFilter.hxx new file mode 100644 index 000000000..c4777573d --- /dev/null +++ b/writerperfect/source/draw/WPGImportFilter.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* "This product is not manufactured, approved, or supported by + * Corel Corporation or Corel Corporation Limited." + */ +#pragma once + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdg.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class WPGImportFilter : public writerperfect::ImportFilter<OdgGenerator> +{ +public: + explicit WPGImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdgGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/ZMFImportFilter.cxx b/writerperfect/source/draw/ZMFImportFilter.cxx new file mode 100644 index 000000000..0d1f16c97 --- /dev/null +++ b/writerperfect/source/draw/ZMFImportFilter.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ZMFImportFilter: Sets up the filter, and calls OdgExporter + * to do the actual filtering + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <libzmf/libzmf.h> + +#include <cppuhelper/supportsservice.hxx> + +#include "ZMFImportFilter.hxx" + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::XInterface; + +bool ZMFImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) +{ + return libzmf::ZMFDocument::parse(&rInput, &rGenerator); +} + +bool ZMFImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + if (libzmf::ZMFDocument::isSupported(&rInput)) + { + rTypeName = "draw_ZMF_Document"; + return true; + } + + return false; +} + +// XServiceInfo +OUString SAL_CALL ZMFImportFilter::getImplementationName() +{ + return "org.libreoffice.comp.Draw.ZMFImportFilter"; +} + +sal_Bool SAL_CALL ZMFImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence<OUString> SAL_CALL ZMFImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_Draw_ZMFImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new ZMFImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/ZMFImportFilter.hxx b/writerperfect/source/draw/ZMFImportFilter.hxx new file mode 100644 index 000000000..686a1fb40 --- /dev/null +++ b/writerperfect/source/draw/ZMFImportFilter.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdg.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class ZMFImportFilter : public writerperfect::ImportFilter<OdgGenerator> +{ +public: + explicit ZMFImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdgGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdgGenerator& rGenerator, utl::MediaDescriptor&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/draw/wpftdraw.component b/writerperfect/source/draw/wpftdraw.component new file mode 100644 index 000000000..1f9ced75a --- /dev/null +++ b/writerperfect/source/draw/wpftdraw.component @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.Draw.CDRImportFilter" + constructor="com_sun_star_comp_Draw_CDRImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="com.sun.star.comp.Draw.CMXImportFilter" + constructor="com_sun_star_comp_Draw_CMXImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="com.sun.star.comp.Draw.FreehandImportFilter" + constructor="com_sun_star_comp_Draw_FreehandImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="com.sun.star.comp.Draw.MSPUBImportFilter" + constructor="com_sun_star_comp_Draw_MSPUBImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="com.sun.star.comp.Draw.MWAWDrawImportFilter" + constructor="com_sun_star_comp_Draw_MWAWDrawImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="org.libreoffice.comp.Draw.StarOfficeDrawImportFilter" + constructor="org_libreoffice_comp_Draw_StarOfficeDrawImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="com.sun.star.comp.Draw.VisioImportFilter" + constructor="com_sun_star_comp_Draw_VisioImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="com.sun.star.comp.Draw.WPGImportFilter" + constructor="com_sun_star_comp_Draw_WPGImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="org.libreoffice.comp.Draw.PageMakerImportFilter" + constructor="org_libreoffice_comp_Draw_PageMakerImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="org.libreoffice.comp.Draw.QXPImportFilter" + constructor="org_libreoffice_comp_Draw_QXPImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="org.libreoffice.comp.Draw.ZMFImportFilter" + constructor="org_libreoffice_comp_Draw_ZMFImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> +</component> diff --git a/writerperfect/source/impress/KeynoteImportFilter.cxx b/writerperfect/source/impress/KeynoteImportFilter.cxx new file mode 100644 index 000000000..ccd93e3d2 --- /dev/null +++ b/writerperfect/source/impress/KeynoteImportFilter.cxx @@ -0,0 +1,247 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* KeynoteImportFilter: Sets up the filter, and calls OdpExporter + * to do the actual filtering + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <memory> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/ucb/XContent.hpp> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <libetonyek/libetonyek.h> +#include <ucbhelper/content.hxx> +#include <unotools/ucbhelper.hxx> + +#include <DirectoryStream.hxx> +#include <WPXSvInputStream.hxx> + +#include "KeynoteImportFilter.hxx" + +using writerperfect::WPXSvInputStream; + +namespace beans = com::sun::star::beans; +namespace ucb = com::sun::star::ucb; + +bool KeynoteImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdpGenerator& rGenerator, utl::MediaDescriptor&) +{ + return libetonyek::EtonyekDocument::parse(&rInput, &rGenerator); +} + +bool KeynoteImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + if (libetonyek::EtonyekDocument::isSupported(&rInput)) + { + rTypeName = "impress_Keynote_Document"; + return true; + } + + return false; +} + +// XExtendedFilterDetection +OUString SAL_CALL +KeynoteImportFilter::detect(css::uno::Sequence<css::beans::PropertyValue>& Descriptor) +{ + sal_Int32 nLength = Descriptor.getLength(); + sal_Int32 nNewLength = nLength + 2; + sal_Int32 nComponentDataLocation = -1; + sal_Int32 nTypeNameLocation = -1; + sal_Int32 nUCBContentLocation = -1; + bool bIsPackage = false; + bool bUCBContentChanged = false; + const beans::PropertyValue* pValue = Descriptor.getConstArray(); + css::uno::Reference<com::sun::star::io::XInputStream> xInputStream; + css::uno::Reference<ucb::XContent> xContent; + css::uno::Sequence<beans::NamedValue> lComponentDataNV; + css::uno::Sequence<beans::PropertyValue> lComponentDataPV; + bool bComponentDataNV = true; + + for (sal_Int32 i = 0; i < nLength; i++) + { + if (pValue[i].Name == "TypeName") + { + nTypeNameLocation = i; + --nNewLength; + } + if (pValue[i].Name == "ComponentData") + { + bComponentDataNV = pValue[i].Value >>= lComponentDataNV; + if (!bComponentDataNV) + pValue[i].Value >>= lComponentDataPV; + nComponentDataLocation = i; + --nNewLength; + } + else if (pValue[i].Name == "InputStream") + { + pValue[i].Value >>= xInputStream; + } + else if (pValue[i].Name == "UCBContent") + { + pValue[i].Value >>= xContent; + nUCBContentLocation = i; + } + } + + assert(nNewLength >= nLength); + + if (!xInputStream.is()) + return OUString(); + + std::unique_ptr<librevenge::RVNGInputStream> input + = std::make_unique<WPXSvInputStream>(xInputStream); + + /* Apple Keynote documents come in two variants: + * * actual files (zip), only produced by Keynote 5 (at least with + * default settings) + * * packages (IOW, directories), produced by Keynote 1-4 and again + * starting with 6. + * But since the libetonyek import only works with a stream, we need + * to pass it one for the whole package. Here we determine if that + * is needed. + * + * Note: for convenience, we also recognize that the main XML file + * from a package was passed and pass the whole package to the + * filter instead. + */ + if (xContent.is()) + { + ucbhelper::Content aContent(xContent, utl::UCBContentHelper::getDefaultCommandEnvironment(), + comphelper::getProcessComponentContext()); + try + { + if (aContent.isFolder()) + { + input = std::make_unique<writerperfect::DirectoryStream>(xContent); + bIsPackage = true; + } + } + catch (...) + { + return OUString(); + } + } + + libetonyek::EtonyekDocument::Type type = libetonyek::EtonyekDocument::TYPE_UNKNOWN; + const libetonyek::EtonyekDocument::Confidence confidence + = libetonyek::EtonyekDocument::isSupported(input.get(), &type); + if ((libetonyek::EtonyekDocument::CONFIDENCE_NONE == confidence) + || (libetonyek::EtonyekDocument::TYPE_KEYNOTE != type)) + return OUString(); + + if (confidence == libetonyek::EtonyekDocument::CONFIDENCE_SUPPORTED_PART) + { + if (bIsPackage) // we passed a directory stream, but the filter claims it's APXL file? + return OUString(); + + std::unique_ptr<writerperfect::DirectoryStream> xDir + = writerperfect::DirectoryStream::createForParent(xContent); + auto pDir = xDir.get(); + input = std::move(xDir); + if (bool(input)) + { + if (libetonyek::EtonyekDocument::CONFIDENCE_EXCELLENT + == libetonyek::EtonyekDocument::isSupported(input.get())) + { + xContent = pDir->getContent(); + bUCBContentChanged = true; + bIsPackage = true; + } + else + { + // The passed stream has been detected as APXL file, but its parent dir is not a valid Keynote + // package? Something is wrong here... + return OUString(); + } + } + } + + // we do not need to insert ComponentData if this is not a package + if (!bIsPackage && (nComponentDataLocation == -1)) + --nNewLength; + + if (nNewLength > nLength) + Descriptor.realloc(nNewLength); + auto pDescriptor = Descriptor.getArray(); + + if (nTypeNameLocation == -1) + { + assert(nLength < nNewLength); + nTypeNameLocation = nLength++; + pDescriptor[nTypeNameLocation].Name = "TypeName"; + } + + if (bIsPackage && (nComponentDataLocation == -1)) + { + assert(nLength < nNewLength); + nComponentDataLocation = nLength++; + pDescriptor[nComponentDataLocation].Name = "ComponentData"; + } + + if (bIsPackage) + { + if (bComponentDataNV) + { + const sal_Int32 nCDSize = lComponentDataNV.getLength(); + lComponentDataNV.realloc(nCDSize + 1); + beans::NamedValue aValue; + aValue.Name = "IsPackage"; + aValue.Value <<= true; + lComponentDataNV.getArray()[nCDSize] = aValue; + pDescriptor[nComponentDataLocation].Value <<= lComponentDataNV; + } + else + { + const sal_Int32 nCDSize = lComponentDataPV.getLength(); + lComponentDataPV.realloc(nCDSize + 1); + beans::PropertyValue aProp; + aProp.Name = "IsPackage"; + aProp.Value <<= true; + aProp.Handle = -1; + aProp.State = beans::PropertyState_DIRECT_VALUE; + lComponentDataPV.getArray()[nCDSize] = aProp; + pDescriptor[nComponentDataLocation].Value <<= lComponentDataPV; + } + } + + if (bUCBContentChanged) + pDescriptor[nUCBContentLocation].Value <<= xContent; + + const OUString sTypeName("impress_AppleKeynote"); + pDescriptor[nTypeNameLocation].Value <<= sTypeName; + + return sTypeName; +} + +// XServiceInfo +OUString SAL_CALL KeynoteImportFilter::getImplementationName() +{ + return "org.libreoffice.comp.Impress.KeynoteImportFilter"; +} + +sal_Bool SAL_CALL KeynoteImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL KeynoteImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_Impress_KeynoteImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new KeynoteImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/impress/KeynoteImportFilter.hxx b/writerperfect/source/impress/KeynoteImportFilter.hxx new file mode 100644 index 000000000..7180a8c86 --- /dev/null +++ b/writerperfect/source/impress/KeynoteImportFilter.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <ImportFilter.hxx> +#include <DocumentHandlerForOdp.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class KeynoteImportFilter : public writerperfect::ImportFilter<OdpGenerator> +{ +public: + explicit KeynoteImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdpGenerator>(rxContext) + { + } + + //XExtendedFilterDetection + virtual OUString SAL_CALL + detect(css::uno::Sequence<css::beans::PropertyValue>& Descriptor) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdpGenerator& rGenerator, utl::MediaDescriptor&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/impress/MWAWPresentationImportFilter.cxx b/writerperfect/source/impress/MWAWPresentationImportFilter.cxx new file mode 100644 index 000000000..c5de6984a --- /dev/null +++ b/writerperfect/source/impress/MWAWPresentationImportFilter.cxx @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* MWAWPresentationImportFilter: Sets up the filter, and calls DocumentCollector + * to do the actual filtering + * + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libmwaw/libmwaw.hxx> + +#include "MWAWPresentationImportFilter.hxx" + +static bool handleEmbeddedMWAWGraphicObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdgGenerator exporter; + exporter.addDocumentHandler(pHandler, streamType); + return MWAWDocument::decodeGraphic(data, &exporter); +} + +static bool handleEmbeddedMWAWSpreadsheetObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdsGenerator exporter; + exporter.registerEmbeddedObjectHandler("image/mwaw-odg", &handleEmbeddedMWAWGraphicObject); + exporter.addDocumentHandler(pHandler, streamType); + return MWAWDocument::decodeSpreadsheet(data, &exporter); +} + +bool MWAWPresentationImportFilter::doImportDocument(weld::Window*, + librevenge::RVNGInputStream& rInput, + OdpGenerator& rGenerator, utl::MediaDescriptor&) +{ + return MWAWDocument::MWAW_R_OK == MWAWDocument::parse(&rInput, &rGenerator); +} + +bool MWAWPresentationImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, + OUString& rTypeName) +{ + rTypeName.clear(); + + MWAWDocument::Type docType = MWAWDocument::MWAW_T_UNKNOWN; + MWAWDocument::Kind docKind = MWAWDocument::MWAW_K_UNKNOWN; + const MWAWDocument::Confidence confidence + = MWAWDocument::isFileFormatSupported(&rInput, docType, docKind); + + if (confidence == MWAWDocument::MWAW_C_EXCELLENT) + { + if (docKind == MWAWDocument::MWAW_K_PRESENTATION) + { + switch (docType) + { + case MWAWDocument::MWAW_T_CLARISWORKS: + rTypeName = "impress_ClarisWorks"; + break; + case MWAWDocument::MWAW_T_RESERVED8: + rTypeName = "impress_PowerPoint3"; + break; + default: + rTypeName = "MWAW_Presentation"; + break; + } + } + } + + return !rTypeName.isEmpty(); +} + +void MWAWPresentationImportFilter::doRegisterHandlers(OdpGenerator& rGenerator) +{ + rGenerator.registerEmbeddedObjectHandler("image/mwaw-odg", &handleEmbeddedMWAWGraphicObject); + rGenerator.registerEmbeddedObjectHandler("image/mwaw-ods", + &handleEmbeddedMWAWSpreadsheetObject); +} + +// XServiceInfo +OUString SAL_CALL MWAWPresentationImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Impress.MWAWPresentationImportFilter"; +} +sal_Bool SAL_CALL MWAWPresentationImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} +css::uno::Sequence<OUString> SAL_CALL MWAWPresentationImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Impress_MWAWPresentationImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new MWAWPresentationImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/impress/MWAWPresentationImportFilter.hxx b/writerperfect/source/impress/MWAWPresentationImportFilter.hxx new file mode 100644 index 000000000..ba6874834 --- /dev/null +++ b/writerperfect/source/impress/MWAWPresentationImportFilter.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdp.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class MWAWPresentationImportFilter : public writerperfect::ImportFilter<OdpGenerator> +{ +public: + explicit MWAWPresentationImportFilter( + const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdpGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdpGenerator& rGenerator, utl::MediaDescriptor&) override; + virtual void doRegisterHandlers(OdpGenerator& rGenerator) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/impress/StarOfficePresentationImportFilter.cxx b/writerperfect/source/impress/StarOfficePresentationImportFilter.cxx new file mode 100644 index 000000000..4f60f57e3 --- /dev/null +++ b/writerperfect/source/impress/StarOfficePresentationImportFilter.cxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libstaroffice/libstaroffice.hxx> + +#include "StarOfficePresentationImportFilter.hxx" + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::XInterface; + +static bool handleEmbeddedSTOFFGraphicObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdgGenerator exporter; + exporter.addDocumentHandler(pHandler, streamType); + return STOFFDocument::decodeGraphic(data, &exporter); +} + +static bool handleEmbeddedSTOFFSpreadsheetObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdsGenerator exporter; + exporter.registerEmbeddedObjectHandler("image/stoff-odg", &handleEmbeddedSTOFFGraphicObject); + exporter.addDocumentHandler(pHandler, streamType); + return STOFFDocument::decodeSpreadsheet(data, &exporter); +} + +bool StarOfficePresentationImportFilter::doImportDocument(weld::Window*, + librevenge::RVNGInputStream& rInput, + OdpGenerator& rGenerator, + utl::MediaDescriptor&) +{ + return STOFFDocument::STOFF_R_OK == STOFFDocument::parse(&rInput, &rGenerator); +} + +bool StarOfficePresentationImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, + OUString& rTypeName) +{ + rTypeName.clear(); + + STOFFDocument::Kind docKind = STOFFDocument::STOFF_K_UNKNOWN; + const STOFFDocument::Confidence confidence + = STOFFDocument::isFileFormatSupported(&rInput, docKind); + + if (confidence == STOFFDocument::STOFF_C_EXCELLENT + || confidence == STOFFDocument::STOFF_C_SUPPORTED_ENCRYPTION) + { + switch (docKind) + { + case STOFFDocument::STOFF_K_PRESENTATION: + rTypeName = "StarOffice_Presentation"; + break; + default: + break; + } + } + + return !rTypeName.isEmpty(); +} + +void StarOfficePresentationImportFilter::doRegisterHandlers(OdpGenerator& rGenerator) +{ + rGenerator.registerEmbeddedObjectHandler("image/stoff-odg", &handleEmbeddedSTOFFGraphicObject); + rGenerator.registerEmbeddedObjectHandler("image/stoff-ods", + &handleEmbeddedSTOFFSpreadsheetObject); +} + +// XServiceInfo +OUString SAL_CALL StarOfficePresentationImportFilter::getImplementationName() +{ + return "org.libreoffice.comp.Impress.StarOfficePresentationImportFilter"; +} + +sal_Bool SAL_CALL StarOfficePresentationImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence<OUString> SAL_CALL StarOfficePresentationImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_Presentation_StarOfficePresentationImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new StarOfficePresentationImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/impress/StarOfficePresentationImportFilter.hxx b/writerperfect/source/impress/StarOfficePresentationImportFilter.hxx new file mode 100644 index 000000000..0f10a9258 --- /dev/null +++ b/writerperfect/source/impress/StarOfficePresentationImportFilter.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdp.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class StarOfficePresentationImportFilter : public writerperfect::ImportFilter<OdpGenerator> +{ +public: + explicit StarOfficePresentationImportFilter( + const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdpGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdpGenerator& rGenerator, utl::MediaDescriptor&) override; + virtual void doRegisterHandlers(OdpGenerator& rGenerator) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/impress/wpftimpress.component b/writerperfect/source/impress/wpftimpress.component new file mode 100644 index 000000000..0f7df39fa --- /dev/null +++ b/writerperfect/source/impress/wpftimpress.component @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="org.libreoffice.comp.Impress.KeynoteImportFilter" + constructor="org_libreoffice_comp_Impress_KeynoteImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="com.sun.star.comp.Impress.MWAWPresentationImportFilter" + constructor="com_sun_star_comp_Impress_MWAWPresentationImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="org.libreoffice.comp.Impress.StarOfficePresentationImportFilter" + constructor="org_libreoffice_comp_Presentation_StarOfficePresentationImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> +</component> diff --git a/writerperfect/source/writer/AbiWordImportFilter.cxx b/writerperfect/source/writer/AbiWordImportFilter.cxx new file mode 100644 index 000000000..0661604bc --- /dev/null +++ b/writerperfect/source/writer/AbiWordImportFilter.cxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* AbiWordImportFilter: Sets up the filter, and calls DocumentCollector + * to do the actual filtering + * + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libabw/libabw.h> + +#include "AbiWordImportFilter.hxx" + +bool AbiWordImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdtGenerator& rGenerator, utl::MediaDescriptor&) +{ + return libabw::AbiDocument::parse(&rInput, &rGenerator); +} + +bool AbiWordImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + if (libabw::AbiDocument::isFileFormatSupported(&rInput)) + { + rTypeName = "writer_AbiWord_Document"; + return true; + } + + return false; +} + +// XServiceInfo +OUString SAL_CALL AbiWordImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Writer.AbiWordImportFilter"; +} + +sal_Bool SAL_CALL AbiWordImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL AbiWordImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Writer_AbiWordImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new AbiWordImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/AbiWordImportFilter.hxx b/writerperfect/source/writer/AbiWordImportFilter.hxx new file mode 100644 index 000000000..f9b0f99d9 --- /dev/null +++ b/writerperfect/source/writer/AbiWordImportFilter.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdt.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class AbiWordImportFilter : public writerperfect::ImportFilter<OdtGenerator> +{ +public: + explicit AbiWordImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdtGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdtGenerator& rGenerator, utl::MediaDescriptor&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/EBookImportFilter.cxx b/writerperfect/source/writer/EBookImportFilter.cxx new file mode 100644 index 000000000..3c53f2d9e --- /dev/null +++ b/writerperfect/source/writer/EBookImportFilter.cxx @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* EBookImportFilter: Sets up the filter, and calls DocumentCollector + * to do the actual filtering + * + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> +#include <sal/log.hxx> + +#include <libe-book/libe-book.h> + +#include "EBookImportFilter.hxx" + +using libebook::EBOOKDocument; + +bool EBookImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdtGenerator& rGenerator, + utl::MediaDescriptor& rDescriptor) +{ + OUString aFilterName; + + rDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] >>= aFilterName; + assert(!aFilterName.isEmpty()); + + if (aFilterName == "Palm_Text_Document") + { + return EBOOKDocument::RESULT_OK == EBOOKDocument::parse(&rInput, &rGenerator); + } + else + { + EBOOKDocument::Type type = EBOOKDocument::TYPE_UNKNOWN; + + if (aFilterName == "BroadBand eBook") + type = EBOOKDocument::TYPE_BBEB; + else if (aFilterName == "FictionBook 2") + type = EBOOKDocument::TYPE_FICTIONBOOK2; + else if (aFilterName == "PalmDoc") + type = EBOOKDocument::TYPE_PALMDOC; + else if (aFilterName == "Plucker eBook") + type = EBOOKDocument::TYPE_PLUCKER; + + if (EBOOKDocument::TYPE_UNKNOWN != type) + return EBOOKDocument::RESULT_OK == EBOOKDocument::parse(&rInput, &rGenerator, type); + } + + return false; +} + +bool EBookImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + rTypeName.clear(); + + EBOOKDocument::Type type = EBOOKDocument::TYPE_UNKNOWN; + + if (EBOOKDocument::CONFIDENCE_EXCELLENT == EBOOKDocument::isSupported(&rInput, &type)) + { + switch (type) + { + case EBOOKDocument::TYPE_BBEB: + rTypeName = "writer_BroadBand_eBook"; + break; + case EBOOKDocument::TYPE_FICTIONBOOK2: + rTypeName = "writer_FictionBook_2"; + break; + case EBOOKDocument::TYPE_PALMDOC: + rTypeName = "writer_PalmDoc"; + break; + case EBOOKDocument::TYPE_PLUCKER: + rTypeName = "writer_Plucker_eBook"; + break; + case EBOOKDocument::TYPE_PEANUTPRESS: + case EBOOKDocument::TYPE_TEALDOC: + case EBOOKDocument::TYPE_ZTXT: + rTypeName = "Palm_Text_Document"; + break; + default: + SAL_WARN_IF(type != EBOOKDocument::TYPE_UNKNOWN, "writerperfect", + "EBookImportFilter::doDetectFormat: document type " + << type << " detected, but ignored"); + } + } + + return !rTypeName.isEmpty(); +} + +// XServiceInfo +OUString SAL_CALL EBookImportFilter::getImplementationName() +{ + return "org.libreoffice.comp.Writer.EBookImportFilter"; +} + +sal_Bool SAL_CALL EBookImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL EBookImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_Writer_EBookImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new EBookImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/EBookImportFilter.hxx b/writerperfect/source/writer/EBookImportFilter.hxx new file mode 100644 index 000000000..9ebdc9234 --- /dev/null +++ b/writerperfect/source/writer/EBookImportFilter.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef EBOOKIMPORTFILTER_HXX +#define EBOOKIMPORTFILTER_HXX + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdt.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class EBookImportFilter : public writerperfect::ImportFilter<OdtGenerator> +{ +public: + explicit EBookImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdtGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdtGenerator& rGenerator, + utl::MediaDescriptor& rDescriptor) override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/EPUBExportDialog.cxx b/writerperfect/source/writer/EPUBExportDialog.cxx new file mode 100644 index 000000000..0bba77a18 --- /dev/null +++ b/writerperfect/source/writer/EPUBExportDialog.cxx @@ -0,0 +1,224 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "EPUBExportDialog.hxx" + +#include <libepubgen/libepubgen.h> + +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> +#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> +#include <comphelper/sequenceashashmap.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/opengrf.hxx> +#include <sax/tools/converter.hxx> +#include <i18nlangtag/languagetag.hxx> + +#include "EPUBExportFilter.hxx" + +using namespace com::sun::star; + +namespace +{ +/// Converts version value to a listbox entry position. +sal_Int32 VersionToPosition(sal_Int32 nVersion) +{ + sal_Int32 nPosition = 0; + + switch (nVersion) + { + case 30: + nPosition = 0; + break; + case 20: + nPosition = 1; + break; + default: + assert(false); + break; + } + + return nPosition; +} + +/// Converts listbox entry position to a version value. +sal_Int32 PositionToVersion(sal_Int32 nPosition) +{ + sal_Int32 nVersion = 0; + + switch (nPosition) + { + case 0: + nVersion = 30; + break; + case 1: + nVersion = 20; + break; + default: + assert(false); + break; + } + + return nVersion; +} +} + +namespace writerperfect +{ +EPUBExportDialog::EPUBExportDialog(weld::Window* pParent, + comphelper::SequenceAsHashMap& rFilterData, + uno::Reference<uno::XComponentContext> xContext, + css::uno::Reference<css::lang::XComponent> xDocument) + : GenericDialogController(pParent, "writerperfect/ui/exportepub.ui", "EpubDialog") + , m_xContext(std::move(xContext)) + , m_rFilterData(rFilterData) + , m_xSourceDocument(std::move(xDocument)) + , m_xVersion(m_xBuilder->weld_combo_box("versionlb")) + , m_xSplit(m_xBuilder->weld_combo_box("splitlb")) + , m_xLayout(m_xBuilder->weld_combo_box("layoutlb")) + , m_xCoverPath(m_xBuilder->weld_entry("coverpath")) + , m_xCoverButton(m_xBuilder->weld_button("coverbutton")) + , m_xMediaDir(m_xBuilder->weld_entry("mediadir")) + , m_xMediaButton(m_xBuilder->weld_button("mediabutton")) + , m_xOKButton(m_xBuilder->weld_button("ok")) + , m_xIdentifier(m_xBuilder->weld_entry("identifier")) + , m_xTitle(m_xBuilder->weld_entry("title")) + , m_xInitialCreator(m_xBuilder->weld_entry("author")) + , m_xLanguage(m_xBuilder->weld_entry("language")) + , m_xDate(m_xBuilder->weld_entry("date")) + +{ + assert(PositionToVersion(m_xVersion->get_active()) == EPUBExportFilter::GetDefaultVersion()); + + auto it = rFilterData.find("EPUBVersion"); + if (it != rFilterData.end()) + { + sal_Int32 nVersion = 0; + if (it->second >>= nVersion) + m_xVersion->set_active(VersionToPosition(nVersion)); + } + m_xVersion->connect_changed(LINK(this, EPUBExportDialog, VersionSelectHdl)); + + it = rFilterData.find("EPUBSplitMethod"); + if (it != rFilterData.end()) + { + sal_Int32 nSplitMethod = 0; + if (it->second >>= nSplitMethod) + // No conversion, 1:1 mapping between libepubgen::EPUBSplitMethod + // and entry positions. + m_xSplit->set_active(nSplitMethod); + } + else + m_xSplit->set_active(EPUBExportFilter::GetDefaultSplitMethod()); + m_xSplit->connect_changed(LINK(this, EPUBExportDialog, SplitSelectHdl)); + + it = rFilterData.find("EPUBLayoutMethod"); + if (it != rFilterData.end()) + { + sal_Int32 nLayoutMethod = 0; + if (it->second >>= nLayoutMethod) + // No conversion, 1:1 mapping between libepubgen::EPUBLayoutMethod + // and entry positions. + m_xLayout->set_active(nLayoutMethod); + } + else + m_xLayout->set_active(EPUBExportFilter::GetDefaultLayoutMethod()); + m_xLayout->connect_changed(LINK(this, EPUBExportDialog, LayoutSelectHdl)); + + m_xCoverButton->connect_clicked(LINK(this, EPUBExportDialog, CoverClickHdl)); + + m_xMediaButton->connect_clicked(LINK(this, EPUBExportDialog, MediaClickHdl)); + + uno::Reference<document::XDocumentPropertiesSupplier> xDPS(m_xSourceDocument, uno::UNO_QUERY); + uno::Reference<document::XDocumentProperties> xDP; + if (xDPS.is()) + xDP = xDPS->getDocumentProperties(); + if (xDP.is()) + { + m_xTitle->set_text(xDP->getTitle()); + m_xInitialCreator->set_text(xDP->getAuthor()); + + OUString aLanguage(LanguageTag::convertToBcp47(xDP->getLanguage(), false)); + m_xLanguage->set_text(aLanguage); + + OUStringBuffer aBuffer; + util::DateTime aDate(xDP->getModificationDate()); + sax::Converter::convertDateTime(aBuffer, aDate, nullptr, true); + m_xDate->set_text(aBuffer.makeStringAndClear()); + } + + m_xOKButton->connect_clicked(LINK(this, EPUBExportDialog, OKClickHdl)); +} + +IMPL_LINK_NOARG(EPUBExportDialog, VersionSelectHdl, weld::ComboBox&, void) +{ + m_rFilterData["EPUBVersion"] <<= PositionToVersion(m_xVersion->get_active()); +} + +IMPL_LINK_NOARG(EPUBExportDialog, SplitSelectHdl, weld::ComboBox&, void) +{ + // No conversion, 1:1 mapping between entry positions and + // libepubgen::EPUBSplitMethod. + m_rFilterData["EPUBSplitMethod"] <<= static_cast<sal_Int32>(m_xSplit->get_active()); +} + +IMPL_LINK_NOARG(EPUBExportDialog, LayoutSelectHdl, weld::ComboBox&, void) +{ + // No conversion, 1:1 mapping between entry positions and + // libepubgen::EPUBLayoutMethod. + m_rFilterData["EPUBLayoutMethod"] <<= static_cast<sal_Int32>(m_xLayout->get_active()); + m_xSplit->set_sensitive(m_xLayout->get_active() != libepubgen::EPUB_LAYOUT_METHOD_FIXED); +} + +IMPL_LINK_NOARG(EPUBExportDialog, CoverClickHdl, weld::Button&, void) +{ + SvxOpenGraphicDialog aDlg("Import", m_xDialog.get()); + aDlg.EnableLink(false); + if (aDlg.Execute() == ERRCODE_NONE) + m_xCoverPath->set_text(aDlg.GetPath()); +} + +IMPL_LINK_NOARG(EPUBExportDialog, MediaClickHdl, weld::Button&, void) +{ + uno::Reference<ui::dialogs::XFolderPicker2> xFolderPicker + = sfx2::createFolderPicker(m_xContext, m_xDialog.get()); + if (xFolderPicker->execute() != ui::dialogs::ExecutableDialogResults::OK) + return; + + m_xMediaDir->set_text(xFolderPicker->getDirectory()); +} + +IMPL_LINK_NOARG(EPUBExportDialog, OKClickHdl, weld::Button&, void) +{ + // General + if (!m_xCoverPath->get_text().isEmpty()) + m_rFilterData["RVNGCoverImage"] <<= m_xCoverPath->get_text(); + if (!m_xMediaDir->get_text().isEmpty()) + m_rFilterData["RVNGMediaDir"] <<= m_xMediaDir->get_text(); + + // Metadata + if (!m_xIdentifier->get_text().isEmpty()) + m_rFilterData["RVNGIdentifier"] <<= m_xIdentifier->get_text(); + if (!m_xTitle->get_text().isEmpty()) + m_rFilterData["RVNGTitle"] <<= m_xTitle->get_text(); + if (!m_xInitialCreator->get_text().isEmpty()) + m_rFilterData["RVNGInitialCreator"] <<= m_xInitialCreator->get_text(); + if (!m_xLanguage->get_text().isEmpty()) + m_rFilterData["RVNGLanguage"] <<= m_xLanguage->get_text(); + if (!m_xDate->get_text().isEmpty()) + m_rFilterData["RVNGDate"] <<= m_xDate->get_text(); + + m_xDialog->response(RET_OK); +} + +EPUBExportDialog::~EPUBExportDialog() = default; + +} // namespace writerperfect + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/EPUBExportDialog.hxx b/writerperfect/source/writer/EPUBExportDialog.hxx new file mode 100644 index 000000000..9e11d5351 --- /dev/null +++ b/writerperfect/source/writer/EPUBExportDialog.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <vcl/weld.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XComponent.hpp> + +namespace comphelper +{ +class SequenceAsHashMap; +} + +namespace writerperfect +{ +/// EPUB export options dialog. +class EPUBExportDialog : public weld::GenericDialogController +{ +public: + EPUBExportDialog(weld::Window* pParent, comphelper::SequenceAsHashMap& rFilterData, + css::uno::Reference<css::uno::XComponentContext> xContext, + css::uno::Reference<css::lang::XComponent> xDocument); + ~EPUBExportDialog() override; + +private: + DECL_LINK(VersionSelectHdl, weld::ComboBox&, void); + DECL_LINK(SplitSelectHdl, weld::ComboBox&, void); + DECL_LINK(LayoutSelectHdl, weld::ComboBox&, void); + DECL_LINK(CoverClickHdl, weld::Button&, void); + DECL_LINK(MediaClickHdl, weld::Button&, void); + DECL_LINK(OKClickHdl, weld::Button&, void); + + css::uno::Reference<css::uno::XComponentContext> m_xContext; + comphelper::SequenceAsHashMap& m_rFilterData; + css::uno::Reference<css::lang::XComponent> m_xSourceDocument; + + std::unique_ptr<weld::ComboBox> m_xVersion; + std::unique_ptr<weld::ComboBox> m_xSplit; + std::unique_ptr<weld::ComboBox> m_xLayout; + std::unique_ptr<weld::Entry> m_xCoverPath; + std::unique_ptr<weld::Button> m_xCoverButton; + std::unique_ptr<weld::Entry> m_xMediaDir; + std::unique_ptr<weld::Button> m_xMediaButton; + std::unique_ptr<weld::Button> m_xOKButton; + std::unique_ptr<weld::Entry> m_xIdentifier; + std::unique_ptr<weld::Entry> m_xTitle; + std::unique_ptr<weld::Entry> m_xInitialCreator; + std::unique_ptr<weld::Entry> m_xLanguage; + std::unique_ptr<weld::Entry> m_xDate; +}; + +} // namespace writerperfect + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/EPUBExportFilter.cxx b/writerperfect/source/writer/EPUBExportFilter.cxx new file mode 100644 index 000000000..8ac55af19 --- /dev/null +++ b/writerperfect/source/writer/EPUBExportFilter.cxx @@ -0,0 +1,206 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "EPUBExportFilter.hxx" + +#include <libepubgen/EPUBTextGenerator.h> +#include <libepubgen/libepubgen-decls.h> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/text/XPageCursor.hpp> +#include <com/sun/star/text/XTextViewCursorSupplier.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <comphelper/genericpropertyset.hxx> +#include <comphelper/propertysetinfo.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <svtools/DocumentToGraphicRenderer.hxx> +#include <vcl/filter/SvmWriter.hxx> +#include <vcl/gdimtf.hxx> +#include <tools/stream.hxx> + +#include "exp/xmlimp.hxx" +#include "EPUBPackage.hxx" + +using namespace com::sun::star; + +namespace writerperfect +{ +EPUBExportFilter::EPUBExportFilter(uno::Reference<uno::XComponentContext> xContext) + : mxContext(std::move(xContext)) +{ +} + +sal_Int32 EPUBExportFilter::GetDefaultVersion() { return 30; } + +sal_Int32 EPUBExportFilter::GetDefaultSplitMethod() +{ + return libepubgen::EPUB_SPLIT_METHOD_HEADING; +} + +sal_Int32 EPUBExportFilter::GetDefaultLayoutMethod() +{ + return libepubgen::EPUB_LAYOUT_METHOD_REFLOWABLE; +} + +sal_Bool EPUBExportFilter::filter(const uno::Sequence<beans::PropertyValue>& rDescriptor) +{ + sal_Int32 nVersion = EPUBExportFilter::GetDefaultVersion(); + sal_Int32 nSplitMethod = EPUBExportFilter::GetDefaultSplitMethod(); + sal_Int32 nLayoutMethod = EPUBExportFilter::GetDefaultLayoutMethod(); + uno::Sequence<beans::PropertyValue> aFilterData; + OUString aFilterOptions; + for (const auto& rProp : rDescriptor) + { + if (rProp.Name == "FilterData") + rProp.Value >>= aFilterData; + else if (rProp.Name == "FilterOptions") + rProp.Value >>= aFilterOptions; + } + + if (aFilterOptions == "layout=fixed") + nLayoutMethod = libepubgen::EPUB_LAYOUT_METHOD_FIXED; + + for (const auto& rProp : std::as_const(aFilterData)) + { + if (rProp.Name == "EPUBVersion") + rProp.Value >>= nVersion; + else if (rProp.Name == "EPUBSplitMethod") + rProp.Value >>= nSplitMethod; + else if (rProp.Name == "EPUBLayoutMethod") + rProp.Value >>= nLayoutMethod; + } + + // Build the export filter chain: the package has direct access to the ZIP + // file, the flat ODF filter has access to the doc model, everything else + // is in-between. + EPUBPackage aPackage(mxContext, rDescriptor); + libepubgen::EPUBTextGenerator aGenerator(&aPackage, nVersion); + aGenerator.setOption(libepubgen::EPUB_GENERATOR_OPTION_SPLIT, nSplitMethod); + aGenerator.setOption(libepubgen::EPUB_GENERATOR_OPTION_LAYOUT, nLayoutMethod); + OUString aSourceURL; + uno::Reference<frame::XModel> xSourceModel(mxSourceDocument, uno::UNO_QUERY); + if (xSourceModel.is()) + aSourceURL = xSourceModel->getURL(); + + std::vector<exp::FixedLayoutPage> aPageMetafiles; + if (nLayoutMethod == libepubgen::EPUB_LAYOUT_METHOD_FIXED) + CreateMetafiles(aPageMetafiles); + + uno::Reference<xml::sax::XDocumentHandler> xExportHandler( + new exp::XMLImport(mxContext, aGenerator, aSourceURL, rDescriptor, aPageMetafiles)); + + uno::Reference<lang::XInitialization> xInitialization( + mxContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.comp.Writer.XMLOasisExporter", mxContext), + uno::UNO_QUERY); + + // A subset of parameters are passed in as a property set. + static comphelper::PropertyMapEntry const aInfoMap[] + = { { OUString("BaseURI"), 0, cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::MAYBEVOID, 0 } }; + uno::Reference<beans::XPropertySet> xInfoSet( + comphelper::GenericPropertySet_CreateInstance(new comphelper::PropertySetInfo(aInfoMap))); + xInfoSet->setPropertyValue("BaseURI", uno::Any(aSourceURL)); + + xInitialization->initialize({ uno::Any(xExportHandler), uno::Any(xInfoSet) }); + uno::Reference<document::XExporter> xExporter(xInitialization, uno::UNO_QUERY); + xExporter->setSourceDocument(mxSourceDocument); + uno::Reference<document::XFilter> xFilter(xInitialization, uno::UNO_QUERY); + + return xFilter->filter(rDescriptor); +} + +void EPUBExportFilter::CreateMetafiles(std::vector<exp::FixedLayoutPage>& rPageMetafiles) +{ + DocumentToGraphicRenderer aRenderer(mxSourceDocument, /*bSelectionOnly=*/false); + uno::Reference<frame::XModel> xModel(mxSourceDocument, uno::UNO_QUERY); + if (!xModel.is()) + return; + + uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier( + xModel->getCurrentController(), uno::UNO_QUERY); + if (!xTextViewCursorSupplier.is()) + return; + + uno::Reference<text::XPageCursor> xCursor(xTextViewCursorSupplier->getViewCursor(), + uno::UNO_QUERY); + if (!xCursor.is()) + return; + + xCursor->jumpToLastPage(); + sal_Int16 nPages = xCursor->getPage(); + for (sal_Int16 nPage = 1; nPage <= nPages; ++nPage) + { + Size aDocumentSizePixel = aRenderer.getDocumentSizeInPixels(nPage); + Size aLogic = aRenderer.getDocumentSizeIn100mm(nPage); + // Get the CSS pixel size of the page (mm100 -> pixel using 96 DPI, independent from system DPI). + Size aCss(static_cast<double>(aLogic.getWidth()) / 26.4583, + static_cast<double>(aLogic.getHeight()) / 26.4583); + Graphic aGraphic = aRenderer.renderToGraphic(nPage, aDocumentSizePixel, aCss, COL_WHITE, + /*bExtOutDevData=*/true); + auto& rGDIMetaFile = const_cast<GDIMetaFile&>(aGraphic.GetGDIMetaFile()); + + // Set preferred map unit and size on the metafile, so the SVG size + // will be correct in MM. + MapMode aMapMode; + aMapMode.SetMapUnit(MapUnit::Map100thMM); + rGDIMetaFile.SetPrefMapMode(aMapMode); + rGDIMetaFile.SetPrefSize(aLogic); + + SvMemoryStream aMemoryStream; + SvmWriter aWriter(aMemoryStream); + aWriter.Write(rGDIMetaFile); + uno::Sequence<sal_Int8> aSequence(static_cast<const sal_Int8*>(aMemoryStream.GetData()), + aMemoryStream.Tell()); + + exp::FixedLayoutPage aPage; + aPage.aMetafile = aSequence; + aPage.aCssPixels = aCss; + aPage.aChapterNames = aRenderer.getChapterNames(); + rPageMetafiles.push_back(aPage); + } +} + +void EPUBExportFilter::cancel() {} + +void EPUBExportFilter::setSourceDocument(const uno::Reference<lang::XComponent>& xDocument) +{ + mxSourceDocument = xDocument; +} + +OUString EPUBExportFilter::getImplementationName() +{ + return "com.sun.star.comp.Writer.EPUBExportFilter"; +} + +sal_Bool EPUBExportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence<OUString> EPUBExportFilter::getSupportedServiceNames() +{ + uno::Sequence<OUString> aRet = { OUString("com.sun.star.document.ExportFilter") }; + return aRet; +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Writer_EPUBExportFilter_get_implementation( + uno::XComponentContext* pContext, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new EPUBExportFilter(pContext)); +} + +} // namespace writerperfect + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/EPUBExportFilter.hxx b/writerperfect/source/writer/EPUBExportFilter.hxx new file mode 100644 index 000000000..6cf007ff4 --- /dev/null +++ b/writerperfect/source/writer/EPUBExportFilter.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <vector> + +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +namespace com::sun::star::uno +{ +class XComponentContext; +} + +namespace writerperfect +{ +namespace exp +{ +struct FixedLayoutPage; +} + +/// EPUB export XFilter implementation. +class EPUBExportFilter + : public cppu::WeakImplHelper<css::document::XFilter, css::document::XExporter, + css::lang::XServiceInfo> +{ + css::uno::Reference<css::uno::XComponentContext> mxContext; + css::uno::Reference<css::lang::XComponent> mxSourceDocument; + +public: + EPUBExportFilter(css::uno::Reference<css::uno::XComponentContext> xContext); + + // XFilter + sal_Bool SAL_CALL + filter(const css::uno::Sequence<css::beans::PropertyValue>& rDescriptor) override; + void SAL_CALL cancel() override; + + // XExporter + void SAL_CALL + setSourceDocument(const css::uno::Reference<css::lang::XComponent>& xDocument) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override; + css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + /// Gives the default EPUB version. + static sal_Int32 GetDefaultVersion(); + /// Gives the default split method. + static sal_Int32 GetDefaultSplitMethod(); + /// Gives the default layout method. + static sal_Int32 GetDefaultLayoutMethod(); + +private: + /// Create page metafiles in case of fixed layout. + void CreateMetafiles(std::vector<exp::FixedLayoutPage>& rPageMetafiles); +}; + +} // namespace writerperfect + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/EPUBExportUIComponent.cxx b/writerperfect/source/writer/EPUBExportUIComponent.cxx new file mode 100644 index 000000000..e8d618b99 --- /dev/null +++ b/writerperfect/source/writer/EPUBExportUIComponent.cxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "EPUBExportUIComponent.hxx" + +#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> +#include <comphelper/namedvaluecollection.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <vcl/svapp.hxx> + +#include "EPUBExportDialog.hxx" + +using namespace com::sun::star; + +namespace writerperfect +{ +EPUBExportUIComponent::EPUBExportUIComponent(uno::Reference<uno::XComponentContext> xContext) + : mxContext(std::move(xContext)) +{ +} + +uno::Sequence<beans::PropertyValue> EPUBExportUIComponent::getPropertyValues() +{ + maMediaDescriptor["FilterData"] <<= maFilterData.getAsConstPropertyValueList(); + return maMediaDescriptor.getAsConstPropertyValueList(); +} + +void EPUBExportUIComponent::setPropertyValues( + const uno::Sequence<beans::PropertyValue>& rProperties) +{ + maMediaDescriptor.clear(); + maMediaDescriptor << rProperties; + auto it = maMediaDescriptor.find("FilterData"); + if (it != maMediaDescriptor.end()) + { + uno::Sequence<beans::PropertyValue> aFilterData; + if (it->second >>= aFilterData) + { + maFilterData.clear(); + maFilterData << aFilterData; + } + } +} + +OUString EPUBExportUIComponent::getImplementationName() +{ + return "com.sun.star.comp.Writer.EPUBExportUIComponent"; +} + +sal_Bool EPUBExportUIComponent::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence<OUString> EPUBExportUIComponent::getSupportedServiceNames() +{ + uno::Sequence<OUString> aRet = { OUString("com.sun.star.ui.dialogs.FilterOptionsDialog") }; + return aRet; +} + +void EPUBExportUIComponent::setTitle(const OUString& /*rTitle*/) {} + +void SAL_CALL EPUBExportUIComponent::initialize(const uno::Sequence<uno::Any>& rArguments) +{ + ::comphelper::NamedValueCollection aProperties(rArguments); + if (aProperties.has("ParentWindow")) + aProperties.get("ParentWindow") >>= mxDialogParent; +} + +sal_Int16 EPUBExportUIComponent::execute() +{ + SolarMutexGuard aGuard; + + EPUBExportDialog aDialog(Application::GetFrameWeld(mxDialogParent), maFilterData, mxContext, + mxSourceDocument); + if (aDialog.run() == RET_OK) + return ui::dialogs::ExecutableDialogResults::OK; + return ui::dialogs::ExecutableDialogResults::CANCEL; +} + +void SAL_CALL EPUBExportUIComponent::setSourceDocument( + const css::uno::Reference<css::lang::XComponent>& xDocument) +{ + mxSourceDocument = xDocument; +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Writer_EPUBExportUIComponent_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new EPUBExportUIComponent(pCtx)); +} + +} // namespace writerperfect + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/EPUBExportUIComponent.hxx b/writerperfect/source/writer/EPUBExportUIComponent.hxx new file mode 100644 index 000000000..71fcc0ace --- /dev/null +++ b/writerperfect/source/writer/EPUBExportUIComponent.hxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/awt/XWindow.hpp> + +#include <comphelper/sequenceashashmap.hxx> +#include <cppuhelper/implbase.hxx> + +namespace com::sun::star::uno +{ +class XComponentContext; +} + +namespace writerperfect +{ +/// EPUB export UI component implementation. +class EPUBExportUIComponent + : public cppu::WeakImplHelper<css::beans::XPropertyAccess, css::lang::XInitialization, + css::lang::XServiceInfo, css::ui::dialogs::XExecutableDialog, + css::document::XExporter> +{ +public: + EPUBExportUIComponent(css::uno::Reference<css::uno::XComponentContext> xContext); + + // XPropertyAccess + css::uno::Sequence<css::beans::PropertyValue> SAL_CALL getPropertyValues() override; + void SAL_CALL + setPropertyValues(const css::uno::Sequence<css::beans::PropertyValue>& rProperties) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override; + css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XExecutableDialog + void SAL_CALL setTitle(const OUString& rTitle) override; + sal_Int16 SAL_CALL execute() override; + + // XExporter + void SAL_CALL + setSourceDocument(const css::uno::Reference<css::lang::XComponent>& xDocument) override; + + // XInitialization + void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override; + +private: + /// The full set of property values. + comphelper::SequenceAsHashMap maMediaDescriptor; + /// The filter data key. + comphelper::SequenceAsHashMap maFilterData; + /// UNO context. + css::uno::Reference<css::uno::XComponentContext> mxContext; + css::uno::Reference<css::lang::XComponent> mxSourceDocument; + css::uno::Reference<css::awt::XWindow> mxDialogParent; +}; + +} // namespace writerperfect + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/EPUBPackage.cxx b/writerperfect/source/writer/EPUBPackage.cxx new file mode 100644 index 000000000..727a8ed7e --- /dev/null +++ b/writerperfect/source/writer/EPUBPackage.cxx @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "EPUBPackage.hxx" + +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/xml/sax/Writer.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp> + +#include <sal/log.hxx> +#include <comphelper/storagehelper.hxx> +#include <unotools/mediadescriptor.hxx> +#include <xmloff/attrlist.hxx> + +using namespace com::sun::star; + +namespace writerperfect +{ +EPUBPackage::EPUBPackage(uno::Reference<uno::XComponentContext> xContext, + const uno::Sequence<beans::PropertyValue>& rDescriptor) + : mxContext(std::move(xContext)) +{ + // Extract the output stream from the descriptor. + utl::MediaDescriptor aMediaDesc(rDescriptor); + auto xStream = aMediaDesc.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_STREAMFOROUTPUT, + uno::Reference<io::XStream>()); + const sal_Int32 nOpenMode = embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE; + mxStorage.set(comphelper::OStorageHelper::GetStorageOfFormatFromStream( + ZIP_STORAGE_FORMAT_STRING, xStream, nOpenMode, mxContext), + uno::UNO_QUERY); + + // The zipped content represents an EPUB Publication. + mxOutputStream.set( + mxStorage->openStreamElementByHierarchicalName("mimetype", embed::ElementModes::READWRITE), + uno::UNO_QUERY); + const OString aMimeType("application/epub+zip"); + uno::Sequence<sal_Int8> aData(reinterpret_cast<const sal_Int8*>(aMimeType.getStr()), + aMimeType.getLength()); + mxOutputStream->writeBytes(aData); + uno::Reference<embed::XTransactedObject> xTransactedObject(mxOutputStream, uno::UNO_QUERY); + xTransactedObject->commit(); + + // MIME type must be uncompressed. + uno::Reference<beans::XPropertySet> xPropertySet(mxOutputStream, uno::UNO_QUERY); + xPropertySet->setPropertyValue("Compressed", uno::Any(false)); + mxOutputStream.clear(); +} + +EPUBPackage::~EPUBPackage() +{ + uno::Reference<embed::XTransactedObject> xTransactedObject(mxStorage, uno::UNO_QUERY); + xTransactedObject->commit(); +} + +void EPUBPackage::openXMLFile(const char* pName) +{ + assert(pName); + assert(!mxOutputStream.is()); + assert(!mxOutputWriter.is()); + + mxOutputStream.set(mxStorage->openStreamElementByHierarchicalName( + OUString::fromUtf8(pName), embed::ElementModes::READWRITE), + uno::UNO_QUERY); + mxOutputWriter = xml::sax::Writer::create(mxContext); + mxOutputWriter->setOutputStream(mxOutputStream); + mxOutputWriter->startDocument(); +} + +void EPUBPackage::openElement(const char* pName, const librevenge::RVNGPropertyList& rAttributes) +{ + assert(mxOutputWriter.is()); + + rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList()); + + librevenge::RVNGPropertyList::Iter it(rAttributes); + for (it.rewind(); it.next();) + pAttributeList->AddAttribute(OUString::fromUtf8(it.key()), + OUString::fromUtf8(it()->getStr().cstr())); + + mxOutputWriter->startElement(OUString::fromUtf8(pName), pAttributeList); +} + +void EPUBPackage::closeElement(const char* pName) +{ + assert(mxOutputWriter.is()); + + mxOutputWriter->endElement(OUString::fromUtf8(pName)); +} + +void EPUBPackage::insertCharacters(const librevenge::RVNGString& rCharacters) +{ + mxOutputWriter->characters(OUString::fromUtf8(rCharacters.cstr())); +} + +void EPUBPackage::closeXMLFile() +{ + assert(mxOutputWriter.is()); + assert(mxOutputStream.is()); + + mxOutputWriter->endDocument(); + mxOutputWriter.clear(); + + uno::Reference<embed::XTransactedObject> xTransactedObject(mxOutputStream, uno::UNO_QUERY); + xTransactedObject->commit(); + mxOutputStream.clear(); +} + +void EPUBPackage::openCSSFile(const char* pName) +{ + assert(pName); + assert(!mxOutputStream.is()); + + mxOutputStream.set(mxStorage->openStreamElementByHierarchicalName( + OUString::fromUtf8(pName), embed::ElementModes::READWRITE), + uno::UNO_QUERY); +} + +void EPUBPackage::insertRule(const librevenge::RVNGString& rSelector, + const librevenge::RVNGPropertyList& rProperties) +{ + assert(mxOutputStream.is()); + + uno::Reference<io::XSeekable> xSeekable(mxOutputStream, uno::UNO_QUERY); + std::stringstream aStream; + if (xSeekable->getPosition() != 0) + aStream << '\n'; + aStream << rSelector.cstr() << " {\n"; + + librevenge::RVNGPropertyList::Iter it(rProperties); + for (it.rewind(); it.next();) + { + if (it()) + aStream << " " << it.key() << ": " << it()->getStr().cstr() << ";\n"; + } + + aStream << "}\n"; + std::string aString = aStream.str(); + uno::Sequence<sal_Int8> aData(reinterpret_cast<const sal_Int8*>(aString.c_str()), + aString.size()); + mxOutputStream->writeBytes(aData); +} + +void EPUBPackage::closeCSSFile() +{ + assert(mxOutputStream.is()); + + uno::Reference<embed::XTransactedObject> xTransactedObject(mxOutputStream, uno::UNO_QUERY); + xTransactedObject->commit(); + mxOutputStream.clear(); +} + +void EPUBPackage::openBinaryFile(const char* pName) +{ + assert(pName); + assert(!mxOutputStream.is()); + + mxOutputStream.set(mxStorage->openStreamElementByHierarchicalName( + OUString::fromUtf8(pName), embed::ElementModes::READWRITE), + uno::UNO_QUERY); +} + +void EPUBPackage::insertBinaryData(const librevenge::RVNGBinaryData& rData) +{ + assert(mxOutputStream.is()); + + if (rData.empty()) + return; + + uno::Sequence<sal_Int8> aData(reinterpret_cast<const sal_Int8*>(rData.getDataBuffer()), + rData.size()); + mxOutputStream->writeBytes(aData); +} + +void EPUBPackage::closeBinaryFile() +{ + assert(mxOutputStream.is()); + + uno::Reference<embed::XTransactedObject> xTransactedObject(mxOutputStream, uno::UNO_QUERY); + xTransactedObject->commit(); + mxOutputStream.clear(); +} + +void EPUBPackage::openTextFile(const char* pName) +{ + SAL_WARN("writerperfect", "EPUBPackage::openTextFile, " << pName << ": implement me"); +} + +void EPUBPackage::insertText(const librevenge::RVNGString& /*rCharacters*/) +{ + SAL_WARN("writerperfect", "EPUBPackage::insertText: implement me"); +} + +void EPUBPackage::insertLineBreak() +{ + SAL_WARN("writerperfect", "EPUBPackage::insertLineBreak: implement me"); +} + +void EPUBPackage::closeTextFile() +{ + SAL_WARN("writerperfect", "EPUBPackage::closeTextFile: implement me"); +} + +} // namespace writerperfect + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/EPUBPackage.hxx b/writerperfect/source/writer/EPUBPackage.hxx new file mode 100644 index 000000000..726d20673 --- /dev/null +++ b/writerperfect/source/writer/EPUBPackage.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <libepubgen/EPUBPackage.h> + +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/uno/Reference.h> + +namespace com::sun::star +{ +namespace beans +{ +struct PropertyValue; +} +namespace embed +{ +class XHierarchicalStorageAccess; +} +namespace io +{ +class XOutputStream; +} +namespace uno +{ +class XComponentContext; +} +namespace xml::sax +{ +class XWriter; +} +} + +namespace writerperfect +{ +/// The epub package has direct access to the resulting ZIP file. +class EPUBPackage : public libepubgen::EPUBPackage +{ + css::uno::Reference<css::uno::XComponentContext> mxContext; + css::uno::Reference<css::embed::XHierarchicalStorageAccess> mxStorage; + css::uno::Reference<css::io::XOutputStream> mxOutputStream; + css::uno::Reference<css::xml::sax::XWriter> mxOutputWriter; + +public: + explicit EPUBPackage(css::uno::Reference<css::uno::XComponentContext> xContext, + const css::uno::Sequence<css::beans::PropertyValue>& rDescriptor); + + ~EPUBPackage() override; + + void openXMLFile(const char* pName) override; + + void openElement(const char* pName, const librevenge::RVNGPropertyList& rAttributes) override; + void closeElement(const char* pName) override; + + void insertCharacters(const librevenge::RVNGString& rCharacters) override; + + void closeXMLFile() override; + + void openCSSFile(const char* pName) override; + + void insertRule(const librevenge::RVNGString& rSelector, + const librevenge::RVNGPropertyList& rProperties) override; + + void closeCSSFile() override; + + void openBinaryFile(const char* pName) override; + + void insertBinaryData(const librevenge::RVNGBinaryData& rData) override; + + void closeBinaryFile() override; + + void openTextFile(const char* pName) override; + + void insertText(const librevenge::RVNGString& rCharacters) override; + + void insertLineBreak() override; + + void closeTextFile() override; +}; + +} // namespace writerperfect + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/MSWorksImportFilter.cxx b/writerperfect/source/writer/MSWorksImportFilter.cxx new file mode 100644 index 000000000..e79120408 --- /dev/null +++ b/writerperfect/source/writer/MSWorksImportFilter.cxx @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* MSWorksImportFilter: Sets up the filter, and calls DocumentCollector + * to do the actual filtering + * + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> +#include <tools/diagnose_ex.h> + +#include <libwps/libwps.h> + +#include <WPFTEncodingDialog.hxx> +#include <WPFTResMgr.hxx> +#include "MSWorksImportFilter.hxx" +#include <strings.hrc> + +static bool handleEmbeddedWKSObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, const OdfStreamType streamType) +{ + OdsGenerator exporter; + exporter.addDocumentHandler(pHandler, streamType); + return libwps::WPSDocument::parse(data.getDataStream(), &exporter) == libwps::WPS_OK; +} + +bool MSWorksImportFilter::doImportDocument(weld::Window* pParent, + librevenge::RVNGInputStream& rInput, + OdtGenerator& rGenerator, + utl::MediaDescriptor& mediaDescriptor) +{ + libwps::WPSKind kind = libwps::WPS_TEXT; + libwps::WPSCreator creator; + bool needEncoding = false; + const libwps::WPSConfidence confidence + = libwps::WPSDocument::isFileFormatSupported(&rInput, kind, creator, needEncoding); + + std::string fileEncoding; + if ((kind == libwps::WPS_TEXT) && (confidence == libwps::WPS_CONFIDENCE_EXCELLENT) + && needEncoding) + { + OUString encoding; + // first check if we can find the encoding in the filter options (headless mode) + mediaDescriptor[utl::MediaDescriptor::PROP_FILTEROPTIONS] >>= encoding; + if (!encoding.isEmpty()) // TODO: check if the encoding string is valid + fileEncoding = encoding.toUtf8().getStr(); + else + { + OUString title; + + switch (creator) + { + case libwps::WPS_MSWORKS: + title = WpResId(STR_ENCODING_DIALOG_TITLE_MSWORKS); + encoding = "CP850"; + break; + case libwps::WPS_RESERVED_0: // MS Write + title = WpResId(STR_ENCODING_DIALOG_TITLE_MSWRITE); + encoding = "CP1252"; + break; + case libwps::WPS_RESERVED_1: // DosWord + title = WpResId(STR_ENCODING_DIALOG_TITLE_DOSWORD); + encoding = "CP850"; + break; + default: + title = WpResId(STR_ENCODING_DIALOG_TITLE); + encoding = "CP850"; + break; + } + + fileEncoding = encoding.toUtf8().getStr(); // set default to the proposed encoding + try + { + writerperfect::WPFTEncodingDialog aDlg(pParent, title, encoding); + if (aDlg.run() == RET_OK) + { + if (!aDlg.GetEncoding().isEmpty()) + fileEncoding = aDlg.GetEncoding().toUtf8().getStr(); + } + // we can fail because we are in headless mode, the user has cancelled conversion, ... + else if (aDlg.hasUserCalledCancel()) + return false; + } + catch (css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("writerperfect", "ignoring"); + } + } + } + return libwps::WPS_OK + == libwps::WPSDocument::parse(&rInput, &rGenerator, "", fileEncoding.c_str()); +} + +bool MSWorksImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + libwps::WPSKind kind = libwps::WPS_TEXT; + libwps::WPSCreator creator; + bool needEncoding; + const libwps::WPSConfidence confidence + = libwps::WPSDocument::isFileFormatSupported(&rInput, kind, creator, needEncoding); + + if ((kind == libwps::WPS_TEXT) && (confidence == libwps::WPS_CONFIDENCE_EXCELLENT)) + { + switch (creator) + { + case libwps::WPS_MSWORKS: + rTypeName = "writer_MS_Works_Document"; + break; + case libwps::WPS_RESERVED_0: + rTypeName = "writer_MS_Write"; + break; + case libwps::WPS_RESERVED_1: + rTypeName = "writer_DosWord"; + break; + case libwps::WPS_RESERVED_4: + rTypeName = "writer_PocketWord_File"; + break; + default: + break; + } + } + + return !rTypeName.isEmpty(); +} + +void MSWorksImportFilter::doRegisterHandlers(OdtGenerator& rGenerator) +{ + rGenerator.registerEmbeddedObjectHandler("image/wks-ods", &handleEmbeddedWKSObject); +} + +// XServiceInfo +OUString SAL_CALL MSWorksImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Writer.MSWorksImportFilter"; +} + +sal_Bool SAL_CALL MSWorksImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL MSWorksImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Writer_MSWorksImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new MSWorksImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/MSWorksImportFilter.hxx b/writerperfect/source/writer/MSWorksImportFilter.hxx new file mode 100644 index 000000000..629904fda --- /dev/null +++ b/writerperfect/source/writer/MSWorksImportFilter.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdt.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class MSWorksImportFilter : public writerperfect::ImportFilter<OdtGenerator> +{ +public: + explicit MSWorksImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdtGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdtGenerator& rGenerator, utl::MediaDescriptor&) override; + virtual void doRegisterHandlers(OdtGenerator& rGenerator) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/MWAWImportFilter.cxx b/writerperfect/source/writer/MWAWImportFilter.cxx new file mode 100644 index 000000000..33fe2d95f --- /dev/null +++ b/writerperfect/source/writer/MWAWImportFilter.cxx @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* MWAWImportFilter: Sets up the filter, and calls DocumentCollector + * to do the actual filtering + * + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libmwaw/libmwaw.hxx> + +#include "MWAWImportFilter.hxx" + +static bool handleEmbeddedMWAWGraphicObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdgGenerator exporter; + exporter.addDocumentHandler(pHandler, streamType); + return MWAWDocument::decodeGraphic(data, &exporter); +} + +static bool handleEmbeddedMWAWSpreadsheetObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdsGenerator exporter; + exporter.registerEmbeddedObjectHandler("image/mwaw-odg", &handleEmbeddedMWAWGraphicObject); + exporter.addDocumentHandler(pHandler, streamType); + return MWAWDocument::decodeSpreadsheet(data, &exporter); +} + +bool MWAWImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdtGenerator& rGenerator, utl::MediaDescriptor&) +{ + return MWAWDocument::MWAW_R_OK == MWAWDocument::parse(&rInput, &rGenerator); +} + +bool MWAWImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + rTypeName.clear(); + + MWAWDocument::Type docType = MWAWDocument::MWAW_T_UNKNOWN; + MWAWDocument::Kind docKind = MWAWDocument::MWAW_K_UNKNOWN; + const MWAWDocument::Confidence confidence + = MWAWDocument::isFileFormatSupported(&rInput, docType, docKind); + + if (confidence == MWAWDocument::MWAW_C_EXCELLENT) + { + if (docKind == MWAWDocument::MWAW_K_TEXT) + { + switch (docType) + { + case MWAWDocument::MWAW_T_CLARISWORKS: + rTypeName = "writer_ClarisWorks"; + break; + case MWAWDocument::MWAW_T_MACWRITE: + case MWAWDocument::MWAW_T_MACWRITEPRO: + rTypeName = "writer_MacWrite"; + break; + case MWAWDocument::MWAW_T_MARINERWRITE: + rTypeName = "writer_Mariner_Write"; + break; + case MWAWDocument::MWAW_T_MICROSOFTWORD: + rTypeName = "writer_Mac_Word"; + break; + case MWAWDocument::MWAW_T_MICROSOFTWORKS: + rTypeName = "writer_Mac_Works"; + break; + case MWAWDocument::MWAW_T_WRITENOW: + rTypeName = "writer_WriteNow"; + break; + default: + rTypeName = "MWAW_Text_Document"; + break; + } + } + } + + return !rTypeName.isEmpty(); +} + +void MWAWImportFilter::doRegisterHandlers(OdtGenerator& rGenerator) +{ + rGenerator.registerEmbeddedObjectHandler("image/mwaw-odg", &handleEmbeddedMWAWGraphicObject); + rGenerator.registerEmbeddedObjectHandler("image/mwaw-ods", + &handleEmbeddedMWAWSpreadsheetObject); +} + +// XServiceInfo +OUString SAL_CALL MWAWImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Writer.MWAWImportFilter"; +} + +sal_Bool SAL_CALL MWAWImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL MWAWImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Writer_MWAWImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new MWAWImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/MWAWImportFilter.hxx b/writerperfect/source/writer/MWAWImportFilter.hxx new file mode 100644 index 000000000..b7bb19268 --- /dev/null +++ b/writerperfect/source/writer/MWAWImportFilter.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdt.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class MWAWImportFilter : public writerperfect::ImportFilter<OdtGenerator> +{ +public: + explicit MWAWImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdtGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdtGenerator& rGenerator, utl::MediaDescriptor&) override; + virtual void doRegisterHandlers(OdtGenerator& rGenerator) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/PagesImportFilter.cxx b/writerperfect/source/writer/PagesImportFilter.cxx new file mode 100644 index 000000000..9d8bb5eb3 --- /dev/null +++ b/writerperfect/source/writer/PagesImportFilter.cxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* PagesImportFilter: Sets up the filter, and calls DocumentCollector + * to do the actual filtering + * + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <libetonyek/libetonyek.h> + +#include <cppuhelper/supportsservice.hxx> + +#include "PagesImportFilter.hxx" + +using libetonyek::EtonyekDocument; + +bool PagesImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput, + OdtGenerator& rGenerator, utl::MediaDescriptor&) +{ + return EtonyekDocument::parse(&rInput, &rGenerator); +} + +bool PagesImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) +{ + EtonyekDocument::Type type = EtonyekDocument::TYPE_UNKNOWN; + const EtonyekDocument::Confidence confidence = EtonyekDocument::isSupported(&rInput, &type); + if ((confidence == EtonyekDocument::CONFIDENCE_EXCELLENT) + && (type == EtonyekDocument::TYPE_PAGES)) + { + rTypeName = "writer_ApplePages"; + return true; + } + + return false; +} + +// XServiceInfo +OUString SAL_CALL PagesImportFilter::getImplementationName() +{ + return "org.libreoffice.comp.Writer.PagesImportFilter"; +} + +sal_Bool SAL_CALL PagesImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL PagesImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_Writer_PagesImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new PagesImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/PagesImportFilter.hxx b/writerperfect/source/writer/PagesImportFilter.hxx new file mode 100644 index 000000000..83fc04618 --- /dev/null +++ b/writerperfect/source/writer/PagesImportFilter.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <DocumentHandlerForOdt.hxx> +#include <ImportFilter.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class PagesImportFilter : public writerperfect::ImportFilter<OdtGenerator> +{ +public: + explicit PagesImportFilter(const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdtGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdtGenerator& rGenerator, + utl::MediaDescriptor& rDescriptor) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/StarOfficeWriterImportFilter.cxx b/writerperfect/source/writer/StarOfficeWriterImportFilter.cxx new file mode 100644 index 000000000..849ede0d7 --- /dev/null +++ b/writerperfect/source/writer/StarOfficeWriterImportFilter.cxx @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppuhelper/supportsservice.hxx> + +#include <libstaroffice/libstaroffice.hxx> + +#include <sfx2/passwd.hxx> + +#include "StarOfficeWriterImportFilter.hxx" + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::XInterface; + +static bool handleEmbeddedSTOFFWriterGraphicObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdgGenerator exporter; + exporter.addDocumentHandler(pHandler, streamType); + return STOFFDocument::decodeGraphic(data, &exporter); +} + +static bool handleEmbeddedSTOFFWriterSpreadsheetObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, + const OdfStreamType streamType) +{ + OdsGenerator exporter; + exporter.registerEmbeddedObjectHandler("image/stoff-odg", + &handleEmbeddedSTOFFWriterGraphicObject); + exporter.addDocumentHandler(pHandler, streamType); + return STOFFDocument::decodeSpreadsheet(data, &exporter); +} + +bool StarOfficeWriterImportFilter::doImportDocument(weld::Window* pParent, + librevenge::RVNGInputStream& rInput, + OdtGenerator& rGenerator, utl::MediaDescriptor&) +{ + STOFFDocument::Kind docKind = STOFFDocument::STOFF_K_UNKNOWN; + const STOFFDocument::Confidence confidence + = STOFFDocument::isFileFormatSupported(&rInput, docKind); + OString aUtf8Passwd; + if (confidence == STOFFDocument::STOFF_C_SUPPORTED_ENCRYPTION) + { + // try to ask for a password + try + { + SfxPasswordDialog aPasswdDlg(pParent); + aPasswdDlg.SetMinLen(0); + if (!aPasswdDlg.run()) + return false; + OUString aPasswd = aPasswdDlg.GetPassword(); + aUtf8Passwd = OUStringToOString(aPasswd, RTL_TEXTENCODING_UTF8); + } + catch (...) + { + // ok, we will probably guess it + } + } + return STOFFDocument::STOFF_R_OK + == STOFFDocument::parse(&rInput, &rGenerator, + !aUtf8Passwd.isEmpty() ? aUtf8Passwd.getStr() : nullptr); +} + +bool StarOfficeWriterImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, + OUString& rTypeName) +{ + rTypeName.clear(); + + STOFFDocument::Kind docKind = STOFFDocument::STOFF_K_UNKNOWN; + const STOFFDocument::Confidence confidence + = STOFFDocument::isFileFormatSupported(&rInput, docKind); + + if (confidence == STOFFDocument::STOFF_C_EXCELLENT + || confidence == STOFFDocument::STOFF_C_SUPPORTED_ENCRYPTION) + { + switch (docKind) + { + case STOFFDocument::STOFF_K_TEXT: + rTypeName = "StarOffice_Writer"; + break; + default: + break; + } + } + + return !rTypeName.isEmpty(); +} + +void StarOfficeWriterImportFilter::doRegisterHandlers(OdtGenerator& rGenerator) +{ + rGenerator.registerEmbeddedObjectHandler("image/stoff-odg", + &handleEmbeddedSTOFFWriterGraphicObject); + rGenerator.registerEmbeddedObjectHandler("image/stoff-ods", + &handleEmbeddedSTOFFWriterSpreadsheetObject); +} + +// XServiceInfo +OUString SAL_CALL StarOfficeWriterImportFilter::getImplementationName() +{ + return "org.libreoffice.comp.Writer.StarOfficeWriterImportFilter"; +} + +sal_Bool SAL_CALL StarOfficeWriterImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence<OUString> SAL_CALL StarOfficeWriterImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_Writer_StarOfficeWriterImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new StarOfficeWriterImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/StarOfficeWriterImportFilter.hxx b/writerperfect/source/writer/StarOfficeWriterImportFilter.hxx new file mode 100644 index 000000000..8310f1cbf --- /dev/null +++ b/writerperfect/source/writer/StarOfficeWriterImportFilter.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <ImportFilter.hxx> + +#include <DocumentHandlerForOdt.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class StarOfficeWriterImportFilter : public writerperfect::ImportFilter<OdtGenerator> +{ +public: + explicit StarOfficeWriterImportFilter( + const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : writerperfect::ImportFilter<OdtGenerator>(rxContext) + { + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + +private: + virtual bool doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName) override; + virtual bool doImportDocument(weld::Window* pParent, librevenge::RVNGInputStream& rInput, + OdtGenerator& rGenerator, utl::MediaDescriptor&) override; + virtual void doRegisterHandlers(OdtGenerator& rGenerator) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/WordPerfectImportFilter.cxx b/writerperfect/source/writer/WordPerfectImportFilter.cxx new file mode 100644 index 000000000..46e3241ee --- /dev/null +++ b/writerperfect/source/writer/WordPerfectImportFilter.cxx @@ -0,0 +1,238 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +/* "This product is not manufactured, approved, or supported by + * Corel Corporation or Corel Corporation Limited." + */ + +#include <osl/diagnose.h> + +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/xml/sax/XFastDocumentHandler.hpp> +#include <com/sun/star/uno/Reference.h> +#include <cppuhelper/supportsservice.hxx> + +#include <DocumentHandler.hxx> +#include <WPXSvInputStream.hxx> + +#include <sfx2/passwd.hxx> +#include <ucbhelper/content.hxx> +#include <vcl/svapp.hxx> +#include <xmloff/xmlimp.hxx> + +#include <libwpd/libwpd.h> +#include <libwpg/libwpg.h> + +#include "WordPerfectImportFilter.hxx" + +using com::sun::star::uno::Reference; + +using com::sun::star::awt::XWindow; +using com::sun::star::document::XImporter; +using com::sun::star::io::XInputStream; +using com::sun::star::xml::sax::XFastDocumentHandler; + +using writerperfect::DocumentHandler; +using writerperfect::WPXSvInputStream; + +static bool handleEmbeddedWPGObject(const librevenge::RVNGBinaryData& data, + OdfDocumentHandler* pHandler, const OdfStreamType streamType) +{ + OdgGenerator exporter; + exporter.addDocumentHandler(pHandler, streamType); + + libwpg::WPGFileFormat fileFormat = libwpg::WPG_AUTODETECT; + + if (!libwpg::WPGraphics::isSupported(data.getDataStream())) + fileFormat = libwpg::WPG_WPG1; + + return libwpg::WPGraphics::parse(data.getDataStream(), &exporter, fileFormat); +} + +static bool handleEmbeddedWPGImage(const librevenge::RVNGBinaryData& input, + librevenge::RVNGBinaryData& output) +{ + libwpg::WPGFileFormat fileFormat = libwpg::WPG_AUTODETECT; + + if (!libwpg::WPGraphics::isSupported(input.getDataStream())) + fileFormat = libwpg::WPG_WPG1; + + librevenge::RVNGStringVector svgOutput; + librevenge::RVNGSVGDrawingGenerator aSVGGenerator(svgOutput, ""); + + if (!libwpg::WPGraphics::parse(input.getDataStream(), &aSVGGenerator, fileFormat)) + return false; + + if (svgOutput.empty()) + return false; + + assert(1 == svgOutput.size()); + + output.clear(); + output.append(reinterpret_cast<const unsigned char*>(svgOutput[0].cstr()), svgOutput[0].size()); + return true; +} + +bool WordPerfectImportFilter::importImpl( + const css::uno::Sequence<css::beans::PropertyValue>& aDescriptor) +{ + Reference<XInputStream> xInputStream; + Reference<XWindow> xDialogParent; + for (const auto& rValue : aDescriptor) + { + if (rValue.Name == "InputStream") + rValue.Value >>= xInputStream; + else if (rValue.Name == "ParentWindow") + rValue.Value >>= xDialogParent; + } + if (!xInputStream.is()) + { + OSL_ASSERT(false); + return false; + } + + WPXSvInputStream input(xInputStream); + + OString aUtf8Passwd; + + libwpd::WPDConfidence confidence = libwpd::WPDocument::isFileFormatSupported(&input); + + if (libwpd::WPD_CONFIDENCE_SUPPORTED_ENCRYPTION == confidence) + { + int unsuccessfulAttempts = 0; + while (true) + { + SfxPasswordDialog aPasswdDlg(Application::GetFrameWeld(xDialogParent)); + aPasswdDlg.SetMinLen(0); + if (!aPasswdDlg.run()) + return false; + OUString aPasswd = aPasswdDlg.GetPassword(); + aUtf8Passwd = OUStringToOString(aPasswd, RTL_TEXTENCODING_UTF8); + if (libwpd::WPD_PASSWORD_MATCH_OK + == libwpd::WPDocument::verifyPassword(&input, aUtf8Passwd.getStr())) + break; + else + unsuccessfulAttempts++; + if (unsuccessfulAttempts == 3) // timeout after 3 password attempts + return false; + } + } + + // An XML import service: what we push sax messages to. + Reference<XInterface> xInternalFilter + = mxContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.comp.Writer.XMLOasisImporter", mxContext); + assert(xInternalFilter); + css::uno::Reference<css::xml::sax::XFastDocumentHandler> xInternalHandler(xInternalFilter, + css::uno::UNO_QUERY); + assert(xInternalHandler); + + // The XImporter sets up an empty target document for XDocumentHandler to write to. + Reference<XImporter> xImporter(xInternalHandler, css::uno::UNO_QUERY); + xImporter->setTargetDocument(mxDoc); + + // OO Document Handler: abstract class to handle document SAX messages, concrete implementation here + // writes to in-memory target doc + DocumentHandler aHandler( + new SvXMLLegacyToFastDocHandler(static_cast<SvXMLImport*>(xInternalHandler.get()))); + + OdtGenerator collector; + collector.addDocumentHandler(&aHandler, ODF_FLAT_XML); + collector.registerEmbeddedObjectHandler("image/x-wpg", &handleEmbeddedWPGObject); + collector.registerEmbeddedImageHandler("image/x-wpg", &handleEmbeddedWPGImage); + return libwpd::WPD_OK + == libwpd::WPDocument::parse(&input, &collector, + aUtf8Passwd.isEmpty() ? nullptr : aUtf8Passwd.getStr()); +} + +sal_Bool SAL_CALL +WordPerfectImportFilter::filter(const css::uno::Sequence<css::beans::PropertyValue>& aDescriptor) +{ + return importImpl(aDescriptor); +} +void SAL_CALL WordPerfectImportFilter::cancel() {} + +// XImporter +void SAL_CALL +WordPerfectImportFilter::setTargetDocument(const Reference<css::lang::XComponent>& xDoc) +{ + mxDoc = xDoc; +} + +// XExtendedFilterDetection +OUString SAL_CALL +WordPerfectImportFilter::detect(css::uno::Sequence<css::beans::PropertyValue>& Descriptor) +{ + libwpd::WPDConfidence confidence = libwpd::WPD_CONFIDENCE_NONE; + OUString sTypeName; + sal_Int32 nLength = Descriptor.getLength(); + sal_Int32 location = nLength; + const css::beans::PropertyValue* pValue = Descriptor.getConstArray(); + Reference<XInputStream> xInputStream; + for (sal_Int32 i = 0; i < nLength; i++) + { + if (pValue[i].Name == "TypeName") + location = i; + else if (pValue[i].Name == "InputStream") + pValue[i].Value >>= xInputStream; + } + + if (!xInputStream.is()) + return OUString(); + + WPXSvInputStream input(xInputStream); + + confidence = libwpd::WPDocument::isFileFormatSupported(&input); + + if (confidence == libwpd::WPD_CONFIDENCE_EXCELLENT + || confidence == libwpd::WPD_CONFIDENCE_SUPPORTED_ENCRYPTION) + sTypeName = "writer_WordPerfect_Document"; + + if (!sTypeName.isEmpty()) + { + if (location == nLength) + { + Descriptor.realloc(nLength + 1); + Descriptor.getArray()[location].Name = "TypeName"; + } + + Descriptor.getArray()[location].Value <<= sTypeName; + } + + return sTypeName; +} + +// XInitialization +void SAL_CALL +WordPerfectImportFilter::initialize(const css::uno::Sequence<css::uno::Any>& /*aArguments*/) +{ +} + +// XServiceInfo +OUString SAL_CALL WordPerfectImportFilter::getImplementationName() +{ + return "com.sun.star.comp.Writer.WordPerfectImportFilter"; +} + +sal_Bool SAL_CALL WordPerfectImportFilter::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL WordPerfectImportFilter::getSupportedServiceNames() +{ + return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Writer_WordPerfectImportFilter_get_implementation( + css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&) +{ + return cppu::acquire(new WordPerfectImportFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/WordPerfectImportFilter.hxx b/writerperfect/source/writer/WordPerfectImportFilter.hxx new file mode 100644 index 000000000..a9fc331ae --- /dev/null +++ b/writerperfect/source/writer/WordPerfectImportFilter.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +/* "This product is not manufactured, approved, or supported by + * Corel Corporation or Corel Corporation Limited." + */ +#pragma once + +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/document/XImporter.hpp> +#include <com/sun/star/document/XExtendedFilterDetection.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/implbase.hxx> + +/* This component will be instantiated for both import or export. Whether it calls + * setSourceDocument or setTargetDocument determines which Impl function the filter + * member calls */ +class WordPerfectImportFilter + : public cppu::WeakImplHelper<css::document::XFilter, css::document::XImporter, + css::document::XExtendedFilterDetection, + css::lang::XInitialization, css::lang::XServiceInfo> +{ + css::uno::Reference<css::uno::XComponentContext> mxContext; + css::uno::Reference<css::lang::XComponent> mxDoc; + + /// @throws css::uno::RuntimeException + bool importImpl(const css::uno::Sequence<css::beans::PropertyValue>& aDescriptor); + +public: + explicit WordPerfectImportFilter( + const css::uno::Reference<css::uno::XComponentContext>& rxContext) + : mxContext(rxContext) + { + } + + // XFilter + virtual sal_Bool SAL_CALL + filter(const css::uno::Sequence<css::beans::PropertyValue>& aDescriptor) override; + virtual void SAL_CALL cancel() override; + + // XImporter + virtual void SAL_CALL + setTargetDocument(const css::uno::Reference<css::lang::XComponent>& xDoc) override; + + //XExtendedFilterDetection + virtual OUString SAL_CALL + detect(css::uno::Sequence<css::beans::PropertyValue>& Descriptor) override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& aArguments) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/XMLBase64ImportContext.cxx b/writerperfect/source/writer/exp/XMLBase64ImportContext.cxx new file mode 100644 index 000000000..a7780e2d5 --- /dev/null +++ b/writerperfect/source/writer/exp/XMLBase64ImportContext.cxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "XMLBase64ImportContext.hxx" + +#include <comphelper/base64.hxx> + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +XMLBase64ImportContext::XMLBase64ImportContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +void XMLBase64ImportContext::startElement( + const OUString& /*rName*/, + const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ +} + +void XMLBase64ImportContext::endElement(const OUString& /*rName*/) +{ + m_aBinaryData.append(static_cast<const unsigned char*>(m_aStream.GetData()), + m_aStream.GetSize()); +} + +void XMLBase64ImportContext::characters(const OUString& rChars) +{ + OUString aTrimmedChars(rChars.trim()); + + if (aTrimmedChars.isEmpty()) + return; + + OUString aChars; + if (!m_aBase64CharsLeft.isEmpty()) + { + aChars = m_aBase64CharsLeft + aTrimmedChars; + m_aBase64CharsLeft.clear(); + } + else + aChars = aTrimmedChars; + + uno::Sequence<sal_Int8> aBuffer((aChars.getLength() / 4) * 3); + const sal_Int32 nCharsDecoded = comphelper::Base64::decodeSomeChars(aBuffer, aChars); + m_aStream.WriteBytes(aBuffer.getArray(), aBuffer.getLength()); + if (nCharsDecoded != aChars.getLength()) + m_aBase64CharsLeft = aChars.copy(nCharsDecoded); +} + +const librevenge::RVNGBinaryData& XMLBase64ImportContext::getBinaryData() const +{ + return m_aBinaryData; +} + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/XMLBase64ImportContext.hxx b/writerperfect/source/writer/exp/XMLBase64ImportContext.hxx new file mode 100644 index 000000000..59558746f --- /dev/null +++ b/writerperfect/source/writer/exp/XMLBase64ImportContext.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <librevenge/RVNGBinaryData.h> + +#include <tools/stream.hxx> + +#include "xmlictxt.hxx" + +namespace writerperfect::exp +{ +/// Handler for <office:binary-data>. +class XMLBase64ImportContext : public XMLImportContext +{ +public: + XMLBase64ImportContext(XMLImport& rImport); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + void SAL_CALL characters(const OUString& rChars) override; + + const librevenge::RVNGBinaryData& getBinaryData() const; + +private: + librevenge::RVNGBinaryData m_aBinaryData; + SvMemoryStream m_aStream; + OUString m_aBase64CharsLeft; +}; + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/XMLFootnoteImportContext.cxx b/writerperfect/source/writer/exp/XMLFootnoteImportContext.cxx new file mode 100644 index 000000000..cdc08c50b --- /dev/null +++ b/writerperfect/source/writer/exp/XMLFootnoteImportContext.cxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "XMLFootnoteImportContext.hxx" + +#include "xmlimp.hxx" +#include "xmltext.hxx" + +#include <sal/log.hxx> + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +namespace +{ +/// Handler for <text:note-citation>. +class XMLTextNoteCitationContext : public XMLImportContext +{ +public: + XMLTextNoteCitationContext(XMLImport& rImport, librevenge::RVNGPropertyList& rProperties); + + void SAL_CALL characters(const OUString& rCharacters) override; + void SAL_CALL endElement(const OUString& rName) override; + +private: + librevenge::RVNGPropertyList& m_rProperties; + OUString m_aCharacters; +}; +} + +XMLTextNoteCitationContext::XMLTextNoteCitationContext(XMLImport& rImport, + librevenge::RVNGPropertyList& rProperties) + : XMLImportContext(rImport) + , m_rProperties(rProperties) +{ +} + +void XMLTextNoteCitationContext::endElement(const OUString& /*rName*/) +{ + m_rProperties.insert("librevenge:number", m_aCharacters.toUtf8().getStr()); +} + +void XMLTextNoteCitationContext::characters(const OUString& rCharacters) +{ + m_aCharacters += rCharacters; +} + +namespace +{ +/// Handler for <text:note-body>. +class XMLFootnoteBodyImportContext : public XMLImportContext +{ +public: + XMLFootnoteBodyImportContext(XMLImport& rImport, + const librevenge::RVNGPropertyList& rProperties); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + +private: + const librevenge::RVNGPropertyList& m_rProperties; +}; +} + +XMLFootnoteBodyImportContext::XMLFootnoteBodyImportContext( + XMLImport& rImport, const librevenge::RVNGPropertyList& rProperties) + : XMLImportContext(rImport) + , m_rProperties(rProperties) +{ +} + +rtl::Reference<XMLImportContext> XMLFootnoteBodyImportContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + return CreateTextChildContext(GetImport(), rName); +} + +void XMLFootnoteBodyImportContext::startElement( + const OUString& /*rName*/, + const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + GetImport().GetGenerator().openFootnote(m_rProperties); +} + +void XMLFootnoteBodyImportContext::endElement(const OUString& /*rName*/) +{ + GetImport().GetGenerator().closeFootnote(); +} + +XMLFootnoteImportContext::XMLFootnoteImportContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +rtl::Reference<XMLImportContext> XMLFootnoteImportContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "text:note-citation") + return new XMLTextNoteCitationContext(GetImport(), m_aProperties); + if (rName == "text:note-body") + return new XMLFootnoteBodyImportContext(GetImport(), m_aProperties); + SAL_WARN("writerperfect", "XMLFootnoteImportContext::CreateChildContext: unhandled " << rName); + return nullptr; +} + +void XMLFootnoteImportContext::startElement( + const OUString& /*rName*/, + const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ +} +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/XMLFootnoteImportContext.hxx b/writerperfect/source/writer/exp/XMLFootnoteImportContext.hxx new file mode 100644 index 000000000..50011d388 --- /dev/null +++ b/writerperfect/source/writer/exp/XMLFootnoteImportContext.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <librevenge/librevenge.h> + +#include <rtl/ref.hxx> + +#include "xmlictxt.hxx" + +namespace writerperfect::exp +{ +/// Handler for <text:note>. +class XMLFootnoteImportContext : public XMLImportContext +{ +public: + XMLFootnoteImportContext(XMLImport& rImport); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + +private: + librevenge::RVNGPropertyList m_aProperties; +}; + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/XMLSectionContext.cxx b/writerperfect/source/writer/exp/XMLSectionContext.cxx new file mode 100644 index 000000000..839400e52 --- /dev/null +++ b/writerperfect/source/writer/exp/XMLSectionContext.cxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "XMLSectionContext.hxx" + +#include "xmlimp.hxx" +#include "xmltext.hxx" + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +XMLSectionContext::XMLSectionContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +rtl::Reference<XMLImportContext> XMLSectionContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + return CreateTextChildContext(GetImport(), rName); +} + +void XMLSectionContext::startElement( + const OUString& /*rName*/, + const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + GetImport().GetGenerator().openSection(librevenge::RVNGPropertyList()); +} + +void XMLSectionContext::endElement(const OUString& /*rName*/) +{ + GetImport().GetGenerator().closeSection(); +} + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/XMLSectionContext.hxx b/writerperfect/source/writer/exp/XMLSectionContext.hxx new file mode 100644 index 000000000..6a1f1e58a --- /dev/null +++ b/writerperfect/source/writer/exp/XMLSectionContext.hxx @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "xmlictxt.hxx" + +namespace writerperfect::exp +{ +/// Handler for <text:section>. +class XMLSectionContext : public XMLImportContext +{ +public: + XMLSectionContext(XMLImport& rImport); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; +}; + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/XMLTextFrameContext.cxx b/writerperfect/source/writer/exp/XMLTextFrameContext.cxx new file mode 100644 index 000000000..4c6ca118e --- /dev/null +++ b/writerperfect/source/writer/exp/XMLTextFrameContext.cxx @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "XMLTextFrameContext.hxx" + +#include "XMLBase64ImportContext.hxx" +#include "txtparai.hxx" +#include "xmlimp.hxx" +#include "xmltext.hxx" + +#include <sal/log.hxx> + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +namespace +{ +/// Handler for <draw:text-box>. +class XMLTextBoxContext : public XMLImportContext +{ +public: + XMLTextBoxContext(XMLImport& rImport); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; +}; +} + +XMLTextBoxContext::XMLTextBoxContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +rtl::Reference<XMLImportContext> XMLTextBoxContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + return CreateTextChildContext(GetImport(), rName); +} + +void XMLTextBoxContext::startElement( + const OUString& /*rName*/, + const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + GetImport().GetGenerator().openTextBox(librevenge::RVNGPropertyList()); +} + +void XMLTextBoxContext::endElement(const OUString& /*rName*/) +{ + GetImport().GetGenerator().closeTextBox(); +} + +namespace +{ +/// Handler for <draw:image>. +class XMLTextImageContext : public XMLImportContext +{ +public: + XMLTextImageContext(XMLImport& rImport); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + +private: + OString m_aMimeType; + rtl::Reference<XMLBase64ImportContext> m_xBinaryData; +}; +} + +XMLTextImageContext::XMLTextImageContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +rtl::Reference<XMLImportContext> XMLTextImageContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "office:binary-data") + { + m_xBinaryData = new XMLBase64ImportContext(GetImport()); + return m_xBinaryData; + } + return nullptr; +} + +void XMLTextImageContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + if (rAttributeName == "loext:mime-type" || rAttributeName == "draw:mime-type") + m_aMimeType = OUStringToOString(xAttribs->getValueByIndex(i), RTL_TEXTENCODING_UTF8); + } +} + +void XMLTextImageContext::endElement(const OUString& /*rName*/) +{ + librevenge::RVNGPropertyList aPropertyList; + + aPropertyList.insert("librevenge:mime-type", m_aMimeType.getStr()); + if (m_xBinaryData.is()) + aPropertyList.insert("office:binary-data", m_xBinaryData->getBinaryData()); + + GetImport().GetGenerator().insertBinaryObject(aPropertyList); +} + +XMLTextFrameContext::XMLTextFrameContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +rtl::Reference<XMLImportContext> XMLTextFrameContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "draw:image") + return new XMLTextImageContext(GetImport()); + if (rName == "draw:text-box") + return new XMLTextBoxContext(GetImport()); + SAL_WARN("writerperfect", "XMLTextFrameContext::CreateChildContext: unhandled " << rName); + return nullptr; +} + +void XMLTextFrameContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + librevenge::RVNGPropertyList aPropertyList; + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + + if (rAttributeName == "draw:style-name") + FillStyles(rAttributeValue, GetImport().GetAutomaticGraphicStyles(), + GetImport().GetGraphicStyles(), aPropertyList); + else + { + OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + aPropertyList.insert(sName.getStr(), sValue.getStr()); + } + } + GetImport().GetGenerator().openFrame(aPropertyList); +} + +void XMLTextFrameContext::endElement(const OUString& /*rName*/) +{ + GetImport().GetGenerator().closeFrame(); +} + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/XMLTextFrameContext.hxx b/writerperfect/source/writer/exp/XMLTextFrameContext.hxx new file mode 100644 index 000000000..9c58849e6 --- /dev/null +++ b/writerperfect/source/writer/exp/XMLTextFrameContext.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <rtl/ref.hxx> + +#include "xmlictxt.hxx" + +namespace writerperfect::exp +{ +class XMLBase64ImportContext; + +/// Handler for <draw:frame>. +class XMLTextFrameContext : public XMLImportContext +{ +public: + XMLTextFrameContext(XMLImport& rImport); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; +}; + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/XMLTextListContext.cxx b/writerperfect/source/writer/exp/XMLTextListContext.cxx new file mode 100644 index 000000000..8798c9a39 --- /dev/null +++ b/writerperfect/source/writer/exp/XMLTextListContext.cxx @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "XMLTextListContext.hxx" + +#include "XMLTextListItemContext.hxx" + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +XMLTextListContext::XMLTextListContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +rtl::Reference<XMLImportContext> XMLTextListContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "text:list-item") + return new XMLTextListItemContext(GetImport()); + return nullptr; +} + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/XMLTextListContext.hxx b/writerperfect/source/writer/exp/XMLTextListContext.hxx new file mode 100644 index 000000000..8a384d7ba --- /dev/null +++ b/writerperfect/source/writer/exp/XMLTextListContext.hxx @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "xmlictxt.hxx" + +namespace writerperfect::exp +{ +/// Handler for <text:list>. +class XMLTextListContext : public XMLImportContext +{ +public: + XMLTextListContext(XMLImport& rImport); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; +}; + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/XMLTextListItemContext.cxx b/writerperfect/source/writer/exp/XMLTextListItemContext.cxx new file mode 100644 index 000000000..36f3f2ce6 --- /dev/null +++ b/writerperfect/source/writer/exp/XMLTextListItemContext.cxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "XMLTextListItemContext.hxx" + +#include "XMLTextListContext.hxx" +#include "txtparai.hxx" + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +XMLTextListItemContext::XMLTextListItemContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +rtl::Reference<XMLImportContext> XMLTextListItemContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "text:p" || rName == "text:h") + return new XMLParaContext(GetImport()); + if (rName == "text:list") + return new XMLTextListContext(GetImport()); + return nullptr; +} + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/XMLTextListItemContext.hxx b/writerperfect/source/writer/exp/XMLTextListItemContext.hxx new file mode 100644 index 000000000..2f17194d4 --- /dev/null +++ b/writerperfect/source/writer/exp/XMLTextListItemContext.hxx @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "xmlictxt.hxx" + +namespace writerperfect::exp +{ +/// Handler for <text:list-item>. +class XMLTextListItemContext : public XMLImportContext +{ +public: + XMLTextListItemContext(XMLImport& rImport); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; +}; + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/txtparai.cxx b/writerperfect/source/writer/exp/txtparai.cxx new file mode 100644 index 000000000..101546c39 --- /dev/null +++ b/writerperfect/source/writer/exp/txtparai.cxx @@ -0,0 +1,634 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <sal/config.h> + +#include "txtparai.hxx" + +#include <string_view> + +#include "XMLFootnoteImportContext.hxx" +#include "XMLTextFrameContext.hxx" +#include "xmlimp.hxx" + +#include <sal/log.hxx> + +using namespace com::sun::star; + +namespace +{ +/// Looks for rName in rStyles and fills rPropertyList based on that +/// (rAutomaticStyles and rNamedStyles are a list of possible parents). +void FillStyle(const OUString& rName, std::map<OUString, librevenge::RVNGPropertyList>& rStyles, + std::map<OUString, librevenge::RVNGPropertyList>& rAutomaticStyles, + std::map<OUString, librevenge::RVNGPropertyList>& rNamedStyles, + librevenge::RVNGPropertyList& rPropertyList) +{ + auto itStyle = rStyles.find(rName); + if (itStyle == rStyles.end()) + return; + + const librevenge::RVNGPropertyList& rStyle = itStyle->second; + if (rStyle["style:parent-style-name"]) + { + // The style has a parent. + OUString aParent = OStringToOUString(rStyle["style:parent-style-name"]->getStr().cstr(), + RTL_TEXTENCODING_UTF8); + if (!aParent.isEmpty()) + writerperfect::exp::FillStyles(aParent, rAutomaticStyles, rNamedStyles, rPropertyList); + } + + // Apply properties from named style. + librevenge::RVNGPropertyList::Iter itProp(rStyle); + for (itProp.rewind(); itProp.next();) + { + if (std::string_view("style:parent-style-name") != itProp.key()) + rPropertyList.insert(itProp.key(), itProp()->clone()); + } +} +} + +namespace writerperfect::exp +{ +namespace +{ +/// Handler for <text:sequence>. +class XMLTextSequenceContext : public XMLImportContext +{ +public: + XMLTextSequenceContext(XMLImport& rImport, const librevenge::RVNGPropertyList& rPropertyList); + + void SAL_CALL characters(const OUString& rChars) override; + +private: + librevenge::RVNGPropertyList m_aPropertyList; +}; +} + +XMLTextSequenceContext::XMLTextSequenceContext(XMLImport& rImport, + const librevenge::RVNGPropertyList& rPropertyList) + : XMLImportContext(rImport) +{ + // Inherit properties from parent. + librevenge::RVNGPropertyList::Iter itProp(rPropertyList); + for (itProp.rewind(); itProp.next();) + m_aPropertyList.insert(itProp.key(), itProp()->clone()); +} + +void XMLTextSequenceContext::characters(const OUString& rChars) +{ + GetImport().GetGenerator().openSpan(m_aPropertyList); + + OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8); + GetImport().GetGenerator().insertText(librevenge::RVNGString(sCharU8.getStr())); + + GetImport().GetGenerator().closeSpan(); +} + +namespace +{ +/// Handler for <text:span>. +class XMLSpanContext : public XMLImportContext +{ +public: + XMLSpanContext(XMLImport& rImport, const librevenge::RVNGPropertyList& rPropertyList); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL characters(const OUString& rChars) override; + +private: + librevenge::RVNGPropertyList m_aPropertyList; +}; +} + +XMLSpanContext::XMLSpanContext(XMLImport& rImport, + const librevenge::RVNGPropertyList& rPropertyList) + : XMLImportContext(rImport) +{ + // Inherit properties from parent. + librevenge::RVNGPropertyList::Iter itProp(rPropertyList); + for (itProp.rewind(); itProp.next();) + m_aPropertyList.insert(itProp.key(), itProp()->clone()); +} + +rtl::Reference<XMLImportContext> XMLSpanContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + return CreateParagraphOrSpanChildContext(GetImport(), rName, m_aPropertyList); +} + +void XMLSpanContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + if (rAttributeName == "text:style-name") + FillStyles(rAttributeValue, GetImport().GetAutomaticTextStyles(), + GetImport().GetTextStyles(), m_aPropertyList); + else + { + OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + m_aPropertyList.insert(sName.getStr(), sValue.getStr()); + } + } +} + +void XMLSpanContext::characters(const OUString& rChars) +{ + GetImport().GetGenerator().openSpan(m_aPropertyList); + + OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8); + GetImport().GetGenerator().insertText(librevenge::RVNGString(sCharU8.getStr())); + + GetImport().GetGenerator().closeSpan(); +} + +namespace +{ +/// Handler for <text:ruby>. +class XMLRubyContext : public XMLImportContext +{ +public: + XMLRubyContext(XMLImport& rImport, const librevenge::RVNGPropertyList& rPropertyList); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL endElement(const OUString& rName) override; + + void SetRubyText(const OUString& rRubyText) { m_sRubyText = rRubyText; } + + OUString& GetRubyBase() { return m_sRubyBase; } + +private: + OUString m_sRubyText; + OUString m_sRubyBase; + librevenge::RVNGPropertyList m_aPropertyList; +}; + +/// Handler for <text:ruby-text>. +class XMLRubyTextContext : public XMLImportContext +{ +public: + XMLRubyTextContext(XMLImport& rImport, XMLRubyContext& rParent) + : XMLImportContext(rImport) + , m_rParent(rParent) + { + } + + void SAL_CALL characters(const OUString& rChars) override { m_rParent.SetRubyText(rChars); } + +private: + XMLRubyContext& m_rParent; +}; + +/// Handler for <text:ruby-base>. +class XMLRubyBaseContext : public XMLImportContext +{ +public: + XMLRubyBaseContext(XMLImport& rImport, XMLRubyContext& rParent) + : XMLImportContext(rImport) + , m_rParent(rParent) + { + } + + void SAL_CALL characters(const OUString& rChars) override { m_rParent.GetRubyBase() += rChars; } + +private: + XMLRubyContext& m_rParent; +}; +} + +XMLRubyContext::XMLRubyContext(XMLImport& rImport, + const librevenge::RVNGPropertyList& rPropertyList) + : XMLImportContext(rImport) +{ + // Inherit properties from parent. + librevenge::RVNGPropertyList::Iter itProp(rPropertyList); + for (itProp.rewind(); itProp.next();) + m_aPropertyList.insert(itProp.key(), itProp()->clone()); +} + +rtl::Reference<XMLImportContext> XMLRubyContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "text:ruby-base") + return new XMLRubyBaseContext(GetImport(), *this); + if (rName == "text:ruby-text") + return new XMLRubyTextContext(GetImport(), *this); + return nullptr; +} + +void XMLRubyContext::endElement(const OUString& /*rName*/) +{ + OString sRubyText = OUStringToOString(m_sRubyText, RTL_TEXTENCODING_UTF8); + OString sRubyBase = OUStringToOString(m_sRubyBase, RTL_TEXTENCODING_UTF8); + if (sRubyText.getLength()) + m_aPropertyList.insert("text:ruby-text", sRubyText.getStr()); + GetImport().GetGenerator().openSpan(m_aPropertyList); + GetImport().GetGenerator().insertText(sRubyBase.getStr()); + GetImport().GetGenerator().closeSpan(); +} + +namespace +{ +/// Base class for contexts that represent a single character only. +class XMLCharContext : public XMLImportContext +{ +public: + XMLCharContext(XMLImport& rImport, const librevenge::RVNGPropertyList& rPropertyList); + + const librevenge::RVNGPropertyList& GetPropertyList() const { return m_aPropertyList; } + +private: + librevenge::RVNGPropertyList m_aPropertyList; +}; +} + +XMLCharContext::XMLCharContext(XMLImport& rImport, + const librevenge::RVNGPropertyList& rPropertyList) + : XMLImportContext(rImport) +{ + // Inherit properties from parent. + librevenge::RVNGPropertyList::Iter itProp(rPropertyList); + for (itProp.rewind(); itProp.next();) + m_aPropertyList.insert(itProp.key(), itProp()->clone()); +} + +namespace +{ +/// Handler for <text:line-break>. +class XMLLineBreakContext : public XMLCharContext +{ +public: + XMLLineBreakContext(XMLImport& rImport, const librevenge::RVNGPropertyList& rPropertyList); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; +}; +} + +XMLLineBreakContext::XMLLineBreakContext(XMLImport& rImport, + const librevenge::RVNGPropertyList& rPropertyList) + : XMLCharContext(rImport, rPropertyList) +{ +} + +void XMLLineBreakContext::startElement( + const OUString& /*rName*/, + const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + GetImport().GetGenerator().openSpan(GetPropertyList()); + GetImport().GetGenerator().insertLineBreak(); + GetImport().GetGenerator().closeSpan(); +} + +namespace +{ +/// Handler for <text:s>. +class XMLSpaceContext : public XMLCharContext +{ +public: + XMLSpaceContext(XMLImport& rImport, const librevenge::RVNGPropertyList& rPropertyList); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; +}; +} + +XMLSpaceContext::XMLSpaceContext(XMLImport& rImport, + const librevenge::RVNGPropertyList& rPropertyList) + : XMLCharContext(rImport, rPropertyList) +{ +} + +void XMLSpaceContext::startElement( + const OUString& /*rName*/, + const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + GetImport().GetGenerator().openSpan(GetPropertyList()); + GetImport().GetGenerator().insertSpace(); + GetImport().GetGenerator().closeSpan(); +} + +namespace +{ +/// Handler for <text:tab>. +class XMLTabContext : public XMLCharContext +{ +public: + XMLTabContext(XMLImport& rImport, const librevenge::RVNGPropertyList& rPropertyList); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; +}; +} + +XMLTabContext::XMLTabContext(XMLImport& rImport, const librevenge::RVNGPropertyList& rPropertyList) + : XMLCharContext(rImport, rPropertyList) +{ +} + +void XMLTabContext::startElement( + const OUString& /*rName*/, + const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + GetImport().GetGenerator().openSpan(GetPropertyList()); + GetImport().GetGenerator().insertTab(); + GetImport().GetGenerator().closeSpan(); +} + +namespace +{ +/// Handler for <draw:a>. +class XMLTextFrameHyperlinkContext : public XMLImportContext +{ +public: + XMLTextFrameHyperlinkContext(XMLImport& rImport, + const librevenge::RVNGPropertyList& rPropertyList); + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + void SAL_CALL characters(const OUString& rChars) override; + +private: + librevenge::RVNGPropertyList m_aPropertyList; + PopupState m_ePopupState = PopupState::NONE; +}; +} + +XMLTextFrameHyperlinkContext::XMLTextFrameHyperlinkContext( + XMLImport& rImport, const librevenge::RVNGPropertyList& rPropertyList) + : XMLImportContext(rImport) +{ + // Inherit properties from parent. + librevenge::RVNGPropertyList::Iter itProp(rPropertyList); + for (itProp.rewind(); itProp.next();) + m_aPropertyList.insert(itProp.key(), itProp()->clone()); +} + +rtl::Reference<XMLImportContext> XMLTextFrameHyperlinkContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + return CreateParagraphOrSpanChildContext(GetImport(), rName, m_aPropertyList); +} + +void XMLTextFrameHyperlinkContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + librevenge::RVNGPropertyList aPropertyList; + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + if (rAttributeName == "text:style-name") + // This affects the nested span's properties. + FillStyles(rAttributeValue, GetImport().GetAutomaticTextStyles(), + GetImport().GetTextStyles(), m_aPropertyList); + else + { + if (rAttributeName == "xlink:href") + { + m_ePopupState = GetImport().FillPopupData(rAttributeValue, aPropertyList); + if (m_ePopupState != PopupState::NotConsumed) + continue; + } + + // This affects the link's properties. + OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + aPropertyList.insert(sName.getStr(), sValue.getStr()); + } + } + + if (m_ePopupState != PopupState::Ignore) + GetImport().GetGenerator().openLink(aPropertyList); +} + +void XMLTextFrameHyperlinkContext::endElement(const OUString& /*rName*/) +{ + if (m_ePopupState != PopupState::Ignore) + GetImport().GetGenerator().closeLink(); +} + +void XMLTextFrameHyperlinkContext::characters(const OUString& rChars) +{ + GetImport().GetGenerator().openSpan(m_aPropertyList); + + OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8); + GetImport().GetGenerator().insertText(librevenge::RVNGString(sCharU8.getStr())); + + GetImport().GetGenerator().closeSpan(); +} + +namespace +{ +/// Handler for <text:a>. +class XMLHyperlinkContext : public XMLImportContext +{ +public: + XMLHyperlinkContext(XMLImport& rImport, const librevenge::RVNGPropertyList& rPropertyList); + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + void SAL_CALL characters(const OUString& rChars) override; + +private: + librevenge::RVNGPropertyList m_aPropertyList; + PopupState m_ePopupState = PopupState::NONE; +}; +} + +XMLHyperlinkContext::XMLHyperlinkContext(XMLImport& rImport, + const librevenge::RVNGPropertyList& rPropertyList) + : XMLImportContext(rImport) +{ + // Inherit properties from parent. + librevenge::RVNGPropertyList::Iter itProp(rPropertyList); + for (itProp.rewind(); itProp.next();) + m_aPropertyList.insert(itProp.key(), itProp()->clone()); +} + +rtl::Reference<XMLImportContext> XMLHyperlinkContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + return CreateParagraphOrSpanChildContext(GetImport(), rName, m_aPropertyList); +} + +void XMLHyperlinkContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + librevenge::RVNGPropertyList aPropertyList; + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + if (rAttributeName == "text:style-name") + // This affects the nested span's properties. + FillStyles(rAttributeValue, GetImport().GetAutomaticTextStyles(), + GetImport().GetTextStyles(), m_aPropertyList); + else + { + if (rAttributeName == "xlink:href") + { + m_ePopupState = GetImport().FillPopupData(rAttributeValue, aPropertyList); + if (m_ePopupState != PopupState::NotConsumed) + continue; + } + + // This affects the link's properties. + OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + aPropertyList.insert(sName.getStr(), sValue.getStr()); + } + } + + if (m_ePopupState != PopupState::Ignore) + GetImport().GetGenerator().openLink(aPropertyList); +} + +void XMLHyperlinkContext::endElement(const OUString& /*rName*/) +{ + if (m_ePopupState != PopupState::Ignore) + GetImport().GetGenerator().closeLink(); +} + +void XMLHyperlinkContext::characters(const OUString& rChars) +{ + GetImport().GetGenerator().openSpan(m_aPropertyList); + + OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8); + GetImport().GetGenerator().insertText(librevenge::RVNGString(sCharU8.getStr())); + + GetImport().GetGenerator().closeSpan(); +} + +XMLParaContext::XMLParaContext(XMLImport& rImport, bool bTopLevel) + : XMLImportContext(rImport) + , m_bTopLevel(bTopLevel) +{ +} + +rtl::Reference<XMLImportContext> XMLParaContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "text:a") + return new XMLHyperlinkContext(GetImport(), m_aTextPropertyList); + if (rName == "draw:a") + return new XMLTextFrameHyperlinkContext(GetImport(), m_aTextPropertyList); + if (rName == "text:ruby") + return new XMLRubyContext(GetImport(), m_aTextPropertyList); + return CreateParagraphOrSpanChildContext(GetImport(), rName, m_aTextPropertyList); +} + +void XMLParaContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + librevenge::RVNGPropertyList aPropertyList; + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + if (rAttributeName == "text:style-name") + { + m_aStyleName = rAttributeValue; + FillStyles(m_aStyleName, GetImport().GetAutomaticParagraphStyles(), + GetImport().GetParagraphStyles(), aPropertyList); + FillStyles(m_aStyleName, GetImport().GetAutomaticTextStyles(), + GetImport().GetTextStyles(), m_aTextPropertyList); + if (m_bTopLevel) + GetImport().HandlePageSpan(aPropertyList); + } + else + { + OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + aPropertyList.insert(sName.getStr(), sValue.getStr()); + } + } + + GetImport().GetGenerator().openParagraph(aPropertyList); +} + +void XMLParaContext::endElement(const OUString& /*rName*/) +{ + GetImport().GetGenerator().closeParagraph(); +} + +void XMLParaContext::characters(const OUString& rChars) +{ + librevenge::RVNGPropertyList aPropertyList; + if (!m_aStyleName.isEmpty()) + FillStyles(m_aStyleName, GetImport().GetAutomaticTextStyles(), GetImport().GetTextStyles(), + aPropertyList); + GetImport().GetGenerator().openSpan(aPropertyList); + + OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8); + GetImport().GetGenerator().insertText(librevenge::RVNGString(sCharU8.getStr())); + + GetImport().GetGenerator().closeSpan(); +} + +rtl::Reference<XMLImportContext> +CreateParagraphOrSpanChildContext(XMLImport& rImport, const OUString& rName, + const librevenge::RVNGPropertyList& rTextPropertyList) +{ + if (rName == "text:span") + return new XMLSpanContext(rImport, rTextPropertyList); + if (rName == "text:line-break") + return new XMLLineBreakContext(rImport, rTextPropertyList); + if (rName == "text:s") + return new XMLSpaceContext(rImport, rTextPropertyList); + if (rName == "text:tab") + return new XMLTabContext(rImport, rTextPropertyList); + if (rName == "draw:frame") + return new XMLTextFrameContext(rImport); + if (rName == "text:sequence") + return new XMLTextSequenceContext(rImport, rTextPropertyList); + if (rName == "text:note") + return new XMLFootnoteImportContext(rImport); + SAL_WARN("writerperfect", "CreateParagraphOrSpanChildContext: unhandled " << rName); + return nullptr; +} + +void FillStyles(const OUString& rName, + std::map<OUString, librevenge::RVNGPropertyList>& rAutomaticStyles, + std::map<OUString, librevenge::RVNGPropertyList>& rNamedStyles, + librevenge::RVNGPropertyList& rPropertyList) +{ + FillStyle(rName, rAutomaticStyles, rAutomaticStyles, rNamedStyles, rPropertyList); + FillStyle(rName, rNamedStyles, rAutomaticStyles, rNamedStyles, rPropertyList); +} + +} // namespace writerperfect + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/txtparai.hxx b/writerperfect/source/writer/exp/txtparai.hxx new file mode 100644 index 000000000..e759dc8f5 --- /dev/null +++ b/writerperfect/source/writer/exp/txtparai.hxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <map> + +#include <librevenge/librevenge.h> + +#include "xmlictxt.hxx" + +namespace writerperfect::exp +{ +/// Handler for <text:p>/<text:h>. +class XMLParaContext : public XMLImportContext +{ +public: + XMLParaContext(XMLImport& rImport, bool bTopLevel = false); + + rtl::Reference<XMLImportContext> CreateChildContext( + const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) override; + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + void SAL_CALL characters(const OUString& rChars) override; + +private: + OUString m_aStyleName; + /// List of properties spans should inherit from this paragraph. + librevenge::RVNGPropertyList m_aTextPropertyList; + /// If the context is a direct child of XMLBodyContentContext. + /// Only direct child of XMLBodyContentContext has to handle page span. + bool m_bTopLevel; +}; + +/// Shared child context factory for paragraph and span contexts. +rtl::Reference<XMLImportContext> +CreateParagraphOrSpanChildContext(XMLImport& rImport, const OUString& rName, + const librevenge::RVNGPropertyList& rTextPropertyList); + +/// Looks for rName in rAutomaticStyles (and failing that, in rNamedStyles) and +/// fills rPropertyList based on that. +void FillStyles(const OUString& rName, + std::map<OUString, librevenge::RVNGPropertyList>& rAutomaticStyles, + std::map<OUString, librevenge::RVNGPropertyList>& rNamedStyles, + librevenge::RVNGPropertyList& rPropertyList); + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/txtstyli.cxx b/writerperfect/source/writer/exp/txtstyli.cxx new file mode 100644 index 000000000..53ac4b4e5 --- /dev/null +++ b/writerperfect/source/writer/exp/txtstyli.cxx @@ -0,0 +1,415 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "txtstyli.hxx" + +#include "xmlfmt.hxx" + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +namespace +{ +/// Handler for <style:paragraph-properties>. +class XMLParagraphPropertiesContext : public XMLImportContext +{ +public: + XMLParagraphPropertiesContext(XMLImport& rImport, XMLStyleContext& rStyle); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + +private: + XMLStyleContext& mrStyle; +}; +} + +XMLParagraphPropertiesContext::XMLParagraphPropertiesContext(XMLImport& rImport, + XMLStyleContext& rStyle) + : XMLImportContext(rImport) + , mrStyle(rStyle) +{ +} + +void XMLParagraphPropertiesContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + OString sName = OUStringToOString(xAttribs->getNameByIndex(i), RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(xAttribs->getValueByIndex(i), RTL_TEXTENCODING_UTF8); + mrStyle.GetParagraphPropertyList().insert(sName.getStr(), sValue.getStr()); + } +} + +namespace +{ +/// Handler for <style:text-properties>. +class XMLTextPropertiesContext : public XMLImportContext +{ +public: + XMLTextPropertiesContext(XMLImport& rImport, XMLStyleContext& rStyle); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + +private: + XMLStyleContext& mrStyle; +}; +} + +XMLTextPropertiesContext::XMLTextPropertiesContext(XMLImport& rImport, XMLStyleContext& rStyle) + : XMLImportContext(rImport) + , mrStyle(rStyle) +{ +} + +void XMLTextPropertiesContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + OString sName = OUStringToOString(xAttribs->getNameByIndex(i), RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(xAttribs->getValueByIndex(i), RTL_TEXTENCODING_UTF8); + mrStyle.GetTextPropertyList().insert(sName.getStr(), sValue.getStr()); + } +} + +namespace +{ +/// Handler for <style:graphic-properties>. +class XMLGraphicPropertiesContext : public XMLImportContext +{ +public: + XMLGraphicPropertiesContext(XMLImport& rImport, XMLStyleContext& rStyle); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + +private: + XMLStyleContext& mrStyle; +}; +} + +XMLGraphicPropertiesContext::XMLGraphicPropertiesContext(XMLImport& rImport, + XMLStyleContext& rStyle) + : XMLImportContext(rImport) + , mrStyle(rStyle) +{ +} + +void XMLGraphicPropertiesContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + OString sName = OUStringToOString(xAttribs->getNameByIndex(i), RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(xAttribs->getValueByIndex(i), RTL_TEXTENCODING_UTF8); + mrStyle.GetGraphicPropertyList().insert(sName.getStr(), sValue.getStr()); + } +} + +namespace +{ +/// Handler for <style:page-layout-properties>. +class XMLPageLayoutPropertiesContext : public XMLImportContext +{ +public: + XMLPageLayoutPropertiesContext(XMLImport& rImport, XMLStyleContext& rStyle); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + +private: + XMLStyleContext& mrStyle; +}; +} + +XMLPageLayoutPropertiesContext::XMLPageLayoutPropertiesContext(XMLImport& rImport, + XMLStyleContext& rStyle) + : XMLImportContext(rImport) + , mrStyle(rStyle) +{ +} + +void XMLPageLayoutPropertiesContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + OString sName = OUStringToOString(xAttribs->getNameByIndex(i), RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(xAttribs->getValueByIndex(i), RTL_TEXTENCODING_UTF8); + // We only care about writing-mode for now. + if (sName != "style:writing-mode") + continue; + + mrStyle.GetPageLayoutPropertyList().insert(sName.getStr(), sValue.getStr()); + } +} + +namespace +{ +/// Handler for <style:table-properties>. +class XMLTablePropertiesContext : public XMLImportContext +{ +public: + XMLTablePropertiesContext(XMLImport& rImport, XMLStyleContext& rStyle); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + +private: + XMLStyleContext& mrStyle; +}; +} + +XMLTablePropertiesContext::XMLTablePropertiesContext(XMLImport& rImport, XMLStyleContext& rStyle) + : XMLImportContext(rImport) + , mrStyle(rStyle) +{ +} + +void XMLTablePropertiesContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + OString sName = OUStringToOString(xAttribs->getNameByIndex(i), RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(xAttribs->getValueByIndex(i), RTL_TEXTENCODING_UTF8); + if (sName == "style:rel-width") + // Make sure this is passed through as a string, and not parsed as a double. + mrStyle.GetTablePropertyList().insert( + sName.getStr(), librevenge::RVNGPropertyFactory::newStringProp(sValue.getStr())); + else + mrStyle.GetTablePropertyList().insert(sName.getStr(), sValue.getStr()); + } +} + +namespace +{ +/// Handler for <style:table-row-properties>. +class XMLTableRowPropertiesContext : public XMLImportContext +{ +public: + XMLTableRowPropertiesContext(XMLImport& rImport, XMLStyleContext& rStyle); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + +private: + XMLStyleContext& mrStyle; +}; +} + +XMLTableRowPropertiesContext::XMLTableRowPropertiesContext(XMLImport& rImport, + XMLStyleContext& rStyle) + : XMLImportContext(rImport) + , mrStyle(rStyle) +{ +} + +void XMLTableRowPropertiesContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + OString sName = OUStringToOString(xAttribs->getNameByIndex(i), RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(xAttribs->getValueByIndex(i), RTL_TEXTENCODING_UTF8); + mrStyle.GetRowPropertyList().insert(sName.getStr(), sValue.getStr()); + } +} + +namespace +{ +/// Handler for <style:table-column-properties>. +class XMLTableColumnPropertiesContext : public XMLImportContext +{ +public: + XMLTableColumnPropertiesContext(XMLImport& rImport, XMLStyleContext& rStyle); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + +private: + XMLStyleContext& mrStyle; +}; +} + +XMLTableColumnPropertiesContext::XMLTableColumnPropertiesContext(XMLImport& rImport, + XMLStyleContext& rStyle) + : XMLImportContext(rImport) + , mrStyle(rStyle) +{ +} + +void XMLTableColumnPropertiesContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + OString sName = OUStringToOString(xAttribs->getNameByIndex(i), RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(xAttribs->getValueByIndex(i), RTL_TEXTENCODING_UTF8); + mrStyle.GetColumnPropertyList().insert(sName.getStr(), sValue.getStr()); + } +} + +namespace +{ +/// Handler for <style:table-cell-properties>. +class XMLTableCellPropertiesContext : public XMLImportContext +{ +public: + XMLTableCellPropertiesContext(XMLImport& rImport, XMLStyleContext& rStyle); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + +private: + XMLStyleContext& mrStyle; +}; +} + +XMLTableCellPropertiesContext::XMLTableCellPropertiesContext(XMLImport& rImport, + XMLStyleContext& rStyle) + : XMLImportContext(rImport) + , mrStyle(rStyle) +{ +} + +void XMLTableCellPropertiesContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + OString sName = OUStringToOString(xAttribs->getNameByIndex(i), RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(xAttribs->getValueByIndex(i), RTL_TEXTENCODING_UTF8); + mrStyle.GetCellPropertyList().insert(sName.getStr(), sValue.getStr()); + } +} + +XMLStyleContext::XMLStyleContext(XMLImport& rImport, XMLStylesContext& rStyles) + : XMLImportContext(rImport) + , m_rStyles(rStyles) +{ +} + +rtl::Reference<XMLImportContext> XMLStyleContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "style:paragraph-properties") + return new XMLParagraphPropertiesContext(GetImport(), *this); + if (rName == "style:text-properties") + return new XMLTextPropertiesContext(GetImport(), *this); + if (rName == "style:table-cell-properties") + return new XMLTableCellPropertiesContext(GetImport(), *this); + if (rName == "style:table-column-properties") + return new XMLTableColumnPropertiesContext(GetImport(), *this); + if (rName == "style:table-row-properties") + return new XMLTableRowPropertiesContext(GetImport(), *this); + if (rName == "style:table-properties") + return new XMLTablePropertiesContext(GetImport(), *this); + if (rName == "style:graphic-properties") + return new XMLGraphicPropertiesContext(GetImport(), *this); + if (rName == "style:page-layout-properties") + return new XMLPageLayoutPropertiesContext(GetImport(), *this); + return nullptr; +} + +void XMLStyleContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + if (rAttributeName == "style:name") + m_aName = rAttributeValue; + else if (rAttributeName == "style:family") + m_aFamily = rAttributeValue; + + // Remember properties of the style itself, e.g. parent name. + OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + m_aTextPropertyList.insert(sName.getStr(), sValue.getStr()); + m_aParagraphPropertyList.insert(sName.getStr(), sValue.getStr()); + m_aGraphicPropertyList.insert(sName.getStr(), sValue.getStr()); + m_aPageLayoutPropertyList.insert(sName.getStr(), sValue.getStr()); + m_aMasterPagePropertyList.insert(sName.getStr(), sValue.getStr()); + m_aTablePropertyList.insert(sName.getStr(), sValue.getStr()); + } +} + +void XMLStyleContext::endElement(const OUString& rName) +{ + if (m_aName.isEmpty()) + return; + + if (m_aFamily == "text" || m_aFamily == "paragraph") + m_rStyles.GetCurrentTextStyles()[m_aName] = m_aTextPropertyList; + if (m_aFamily == "paragraph") + m_rStyles.GetCurrentParagraphStyles()[m_aName] = m_aParagraphPropertyList; + else if (m_aFamily == "table-cell") + m_rStyles.GetCurrentCellStyles()[m_aName] = m_aCellPropertyList; + else if (m_aFamily == "table-column") + m_rStyles.GetCurrentColumnStyles()[m_aName] = m_aColumnPropertyList; + else if (m_aFamily == "table-row") + m_rStyles.GetCurrentRowStyles()[m_aName] = m_aRowPropertyList; + else if (m_aFamily == "table") + m_rStyles.GetCurrentTableStyles()[m_aName] = m_aTablePropertyList; + else if (m_aFamily == "graphic") + m_rStyles.GetCurrentGraphicStyles()[m_aName] = m_aGraphicPropertyList; + else if (rName == "style:page-layout") + m_rStyles.GetCurrentPageLayouts()[m_aName] = m_aPageLayoutPropertyList; + else if (rName == "style:master-page") + m_rStyles.GetCurrentMasterStyles()[m_aName] = m_aMasterPagePropertyList; +} + +librevenge::RVNGPropertyList& XMLStyleContext::GetTextPropertyList() { return m_aTextPropertyList; } + +librevenge::RVNGPropertyList& XMLStyleContext::GetParagraphPropertyList() +{ + return m_aParagraphPropertyList; +} + +librevenge::RVNGPropertyList& XMLStyleContext::GetCellPropertyList() { return m_aCellPropertyList; } + +librevenge::RVNGPropertyList& XMLStyleContext::GetColumnPropertyList() +{ + return m_aColumnPropertyList; +} + +librevenge::RVNGPropertyList& XMLStyleContext::GetRowPropertyList() { return m_aRowPropertyList; } + +librevenge::RVNGPropertyList& XMLStyleContext::GetTablePropertyList() +{ + return m_aTablePropertyList; +} + +librevenge::RVNGPropertyList& XMLStyleContext::GetGraphicPropertyList() +{ + return m_aGraphicPropertyList; +} + +librevenge::RVNGPropertyList& XMLStyleContext::GetPageLayoutPropertyList() +{ + return m_aPageLayoutPropertyList; +} + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/txtstyli.hxx b/writerperfect/source/writer/exp/txtstyli.hxx new file mode 100644 index 000000000..9247619bc --- /dev/null +++ b/writerperfect/source/writer/exp/txtstyli.hxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <librevenge/librevenge.h> + +#include "xmlictxt.hxx" + +namespace writerperfect::exp +{ +class XMLStylesContext; + +/// Handler for <style:style>. +class XMLStyleContext : public XMLImportContext +{ +public: + XMLStyleContext(XMLImport& rImport, XMLStylesContext& rStyles); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + + librevenge::RVNGPropertyList& GetTextPropertyList(); + librevenge::RVNGPropertyList& GetParagraphPropertyList(); + librevenge::RVNGPropertyList& GetCellPropertyList(); + librevenge::RVNGPropertyList& GetColumnPropertyList(); + librevenge::RVNGPropertyList& GetRowPropertyList(); + librevenge::RVNGPropertyList& GetTablePropertyList(); + librevenge::RVNGPropertyList& GetGraphicPropertyList(); + librevenge::RVNGPropertyList& GetPageLayoutPropertyList(); + +private: + OUString m_aName; + OUString m_aFamily; + librevenge::RVNGPropertyList m_aTextPropertyList; + librevenge::RVNGPropertyList m_aParagraphPropertyList; + librevenge::RVNGPropertyList m_aCellPropertyList; + librevenge::RVNGPropertyList m_aColumnPropertyList; + librevenge::RVNGPropertyList m_aRowPropertyList; + librevenge::RVNGPropertyList m_aTablePropertyList; + librevenge::RVNGPropertyList m_aGraphicPropertyList; + librevenge::RVNGPropertyList m_aPageLayoutPropertyList; + librevenge::RVNGPropertyList m_aMasterPagePropertyList; + XMLStylesContext& m_rStyles; +}; + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/xmlfmt.cxx b/writerperfect/source/writer/exp/xmlfmt.cxx new file mode 100644 index 000000000..4ac70b85a --- /dev/null +++ b/writerperfect/source/writer/exp/xmlfmt.cxx @@ -0,0 +1,295 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "xmlfmt.hxx" + +#include "XMLBase64ImportContext.hxx" +#include "txtstyli.hxx" +#include "xmlimp.hxx" + +#include <sal/log.hxx> + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +XMLStylesContext::XMLStylesContext(XMLImport& rImport, StyleType eType) + : XMLImportContext(rImport) + , m_rParagraphStyles(eType == StyleType_AUTOMATIC ? GetImport().GetAutomaticParagraphStyles() + : GetImport().GetParagraphStyles()) + , m_rTextStyles(eType == StyleType_AUTOMATIC ? GetImport().GetAutomaticTextStyles() + : GetImport().GetTextStyles()) + , m_rCellStyles(eType == StyleType_AUTOMATIC ? GetImport().GetAutomaticCellStyles() + : GetImport().GetCellStyles()) + , m_rColumnStyles(eType == StyleType_AUTOMATIC ? GetImport().GetAutomaticColumnStyles() + : GetImport().GetColumnStyles()) + , m_rRowStyles(eType == StyleType_AUTOMATIC ? GetImport().GetAutomaticRowStyles() + : GetImport().GetRowStyles()) + , m_rTableStyles(eType == StyleType_AUTOMATIC ? GetImport().GetAutomaticTableStyles() + : GetImport().GetTableStyles()) + , m_rGraphicStyles(eType == StyleType_AUTOMATIC ? GetImport().GetAutomaticGraphicStyles() + : GetImport().GetGraphicStyles()) + , m_rPageLayouts(GetImport().GetPageLayouts()) + , m_rMasterStyles(GetImport().GetMasterStyles()) +{ +} + +rtl::Reference<XMLImportContext> XMLStylesContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "style:style" || rName == "style:page-layout" || rName == "style:master-page") + return new XMLStyleContext(GetImport(), *this); + return nullptr; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLStylesContext::GetCurrentParagraphStyles() +{ + return m_rParagraphStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLStylesContext::GetCurrentTextStyles() +{ + return m_rTextStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLStylesContext::GetCurrentCellStyles() +{ + return m_rCellStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLStylesContext::GetCurrentColumnStyles() +{ + return m_rColumnStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLStylesContext::GetCurrentRowStyles() +{ + return m_rRowStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLStylesContext::GetCurrentTableStyles() +{ + return m_rTableStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLStylesContext::GetCurrentGraphicStyles() +{ + return m_rGraphicStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLStylesContext::GetCurrentPageLayouts() +{ + return m_rPageLayouts; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLStylesContext::GetCurrentMasterStyles() +{ + return m_rMasterStyles; +} + +namespace +{ +/// Handler for <style:font-face>. +class XMLFontFaceContext : public XMLImportContext +{ +public: + XMLFontFaceContext(XMLImport& rImport); + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + OUString const& GetName() const { return maName; } + +private: + OUString maName; +}; + +/// Handler for <svg:font-face-src>. +class XMLFontFaceSrcContext : public XMLImportContext +{ +public: + XMLFontFaceSrcContext(XMLImport& rImport, XMLFontFaceContext& rFontFace); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + +private: + XMLFontFaceContext& mrFontFace; +}; + +/// Handler for <svg:font-face-uri>. +class XMLFontFaceUriContext : public XMLImportContext +{ +public: + XMLFontFaceUriContext(XMLImport& rImport, XMLFontFaceContext const& rFontFace); + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + librevenge::RVNGPropertyList& GetPropertyList() { return maPropertyList; } + +private: + librevenge::RVNGPropertyList maPropertyList; + rtl::Reference<XMLBase64ImportContext> mxBinaryData; +}; + +/// Handler for <svg:font-face-format>. +class XMLFontFaceFormatContext : public XMLImportContext +{ +public: + XMLFontFaceFormatContext(XMLImport& rImport, XMLFontFaceUriContext& rFontFaceUri); + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + +private: + XMLFontFaceUriContext& mrFontFaceUri; +}; +} + +XMLFontFaceFormatContext::XMLFontFaceFormatContext(XMLImport& rImport, + XMLFontFaceUriContext& rFontFaceUri) + : XMLImportContext(rImport) + , mrFontFaceUri(rFontFaceUri) +{ +} + +void XMLFontFaceFormatContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + if (rAttributeName == "svg:string") + { + OString aAttributeValueU8 = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + mrFontFaceUri.GetPropertyList().insert("librevenge:mime-type", + aAttributeValueU8.getStr()); + } + } +} + +XMLFontFaceUriContext::XMLFontFaceUriContext(XMLImport& rImport, + XMLFontFaceContext const& rFontFace) + : XMLImportContext(rImport) +{ + OString aNameU8 = OUStringToOString(rFontFace.GetName(), RTL_TEXTENCODING_UTF8); + maPropertyList.insert("librevenge:name", aNameU8.getStr()); +} + +void XMLFontFaceUriContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + if (rAttributeName == "loext:font-style") + { + OString aAttributeValueU8 = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + maPropertyList.insert("librevenge:font-style", aAttributeValueU8.getStr()); + } + else if (rAttributeName == "loext:font-weight") + { + OString aAttributeValueU8 = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + maPropertyList.insert("librevenge:font-weight", aAttributeValueU8.getStr()); + } + } +} + +void XMLFontFaceUriContext::endElement(const OUString& /*rName*/) +{ + if (mxBinaryData.is()) + maPropertyList.insert("office:binary-data", mxBinaryData->getBinaryData()); + GetImport().GetGenerator().defineEmbeddedFont(maPropertyList); +} + +rtl::Reference<XMLImportContext> XMLFontFaceUriContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "office:binary-data") + { + mxBinaryData = new XMLBase64ImportContext(GetImport()); + return mxBinaryData; + } + if (rName == "svg:font-face-format") + return new XMLFontFaceFormatContext(GetImport(), *this); + + SAL_WARN("writerperfect", "XMLFontFaceUriContext::CreateChildContext: unhandled " << rName); + return nullptr; +} + +XMLFontFaceSrcContext::XMLFontFaceSrcContext(XMLImport& rImport, XMLFontFaceContext& rFontFace) + : XMLImportContext(rImport) + , mrFontFace(rFontFace) +{ +} + +rtl::Reference<XMLImportContext> XMLFontFaceSrcContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "svg:font-face-uri") + return new XMLFontFaceUriContext(GetImport(), mrFontFace); + SAL_WARN("writerperfect", "XMLFontFaceSrcContext::CreateChildContext: unhandled " << rName); + return nullptr; +} + +XMLFontFaceContext::XMLFontFaceContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +void XMLFontFaceContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + if (rAttributeName == "style:name") + maName = rAttributeValue; + } +} + +rtl::Reference<XMLImportContext> XMLFontFaceContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "svg:font-face-src") + return new XMLFontFaceSrcContext(GetImport(), *this); + SAL_WARN("writerperfect", "XMLFontFaceContext::CreateChildContext: unhandled " << rName); + return nullptr; +} + +XMLFontFaceDeclsContext::XMLFontFaceDeclsContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +rtl::Reference<XMLImportContext> XMLFontFaceDeclsContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "style:font-face") + return new XMLFontFaceContext(GetImport()); + return nullptr; +} + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/xmlfmt.hxx b/writerperfect/source/writer/exp/xmlfmt.hxx new file mode 100644 index 000000000..22849be7e --- /dev/null +++ b/writerperfect/source/writer/exp/xmlfmt.hxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <map> + +#include "xmlictxt.hxx" + +namespace librevenge +{ +class RVNGPropertyList; +} + +namespace writerperfect::exp +{ +/// Handler for <office:automatic-styles>/<office:styles>. +class XMLStylesContext : public XMLImportContext +{ +public: + enum StyleType + { + StyleType_NONE, + StyleType_AUTOMATIC + }; + XMLStylesContext(XMLImport& rImport, StyleType eType); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentParagraphStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentTextStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentCellStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentColumnStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentRowStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentTableStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentGraphicStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentPageLayouts(); + std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentMasterStyles(); + +private: + std::map<OUString, librevenge::RVNGPropertyList>& m_rParagraphStyles; + std::map<OUString, librevenge::RVNGPropertyList>& m_rTextStyles; + std::map<OUString, librevenge::RVNGPropertyList>& m_rCellStyles; + std::map<OUString, librevenge::RVNGPropertyList>& m_rColumnStyles; + std::map<OUString, librevenge::RVNGPropertyList>& m_rRowStyles; + std::map<OUString, librevenge::RVNGPropertyList>& m_rTableStyles; + std::map<OUString, librevenge::RVNGPropertyList>& m_rGraphicStyles; + std::map<OUString, librevenge::RVNGPropertyList>& m_rPageLayouts; + std::map<OUString, librevenge::RVNGPropertyList>& m_rMasterStyles; +}; + +/// Handler for <office:font-face-decls>. +class XMLFontFaceDeclsContext : public XMLImportContext +{ +public: + XMLFontFaceDeclsContext(XMLImport& rImport); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; +}; + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/xmlictxt.cxx b/writerperfect/source/writer/exp/xmlictxt.cxx new file mode 100644 index 000000000..ebfe58402 --- /dev/null +++ b/writerperfect/source/writer/exp/xmlictxt.cxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "xmlictxt.hxx" + +#include "xmlimp.hxx" + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +XMLImportContext::XMLImportContext(XMLImport& rImport) + : mrImport(rImport) +{ +} + +rtl::Reference<XMLImportContext> XMLImportContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + return mrImport.CreateContext(rName, xAttribs); +} + +void XMLImportContext::startDocument() {} + +void XMLImportContext::endDocument() {} + +void XMLImportContext::startElement( + const OUString& /*rName*/, + const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ +} + +void XMLImportContext::endElement(const OUString& /*rName*/) {} + +void XMLImportContext::characters(const OUString& /*rChars*/) {} + +void XMLImportContext::ignorableWhitespace(const OUString& /*rWhitespaces*/) {} + +void XMLImportContext::processingInstruction(const OUString& /*rTarget*/, const OUString& /*rData*/) +{ +} + +void XMLImportContext::setDocumentLocator( + const css::uno::Reference<css::xml::sax::XLocator>& /*xLocator*/) +{ +} + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/xmlictxt.hxx b/writerperfect/source/writer/exp/xmlictxt.hxx new file mode 100644 index 000000000..dc05449d3 --- /dev/null +++ b/writerperfect/source/writer/exp/xmlictxt.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> + +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> + +namespace writerperfect::exp +{ +class XMLImport; + +/// Base class for a handler of a single XML element during ODF -> librevenge conversion. +class XMLImportContext : public cppu::WeakImplHelper<css::xml::sax::XDocumentHandler> +{ +public: + XMLImportContext(XMLImport& rImport); + XMLImport& GetImport() { return mrImport; } + + virtual rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs); + + // XDocumentHandler + void SAL_CALL startDocument() override; + void SAL_CALL endDocument() override; + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + void SAL_CALL characters(const OUString& rChars) override; + void SAL_CALL ignorableWhitespace(const OUString& rWhitespaces) override; + void SAL_CALL processingInstruction(const OUString& rTarget, const OUString& rData) override; + void SAL_CALL + setDocumentLocator(const css::uno::Reference<css::xml::sax::XLocator>& xLocator) override; + +private: + XMLImport& mrImport; +}; + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/xmlimp.cxx b/writerperfect/source/writer/exp/xmlimp.cxx new file mode 100644 index 000000000..ae7b33518 --- /dev/null +++ b/writerperfect/source/writer/exp/xmlimp.cxx @@ -0,0 +1,621 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <sal/config.h> + +#include "xmlimp.hxx" + +#include <string_view> + +#include <initializer_list> +#include <unordered_map> + +#include <com/sun/star/svg/XSVGWriter.hpp> +#include <com/sun/star/uri/UriReferenceFactory.hpp> +#include <com/sun/star/xml/sax/InputSource.hpp> +#include <com/sun/star/xml/sax/Parser.hpp> +#include <com/sun/star/xml/sax/Writer.hpp> +#include <comphelper/propertyvalue.hxx> +#include <rtl/uri.hxx> +#include <tools/gen.hxx> +#include <tools/stream.hxx> +#include <tools/urlobj.hxx> +#include <unotools/streamwrap.hxx> +#include <tools/diagnose_ex.h> + +#include "xmlfmt.hxx" +#include "xmlictxt.hxx" +#include "xmlmetai.hxx" +#include "xmltext.hxx" + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +namespace +{ +/// Looks up mime type for a given image extension. +OUString GetMimeType(const OUString& rExtension) +{ + static const std::unordered_map<OUString, OUString> vMimeTypes = { + { "gif", "image/gif" }, + { "jpg", "image/jpeg" }, + { "png", "image/png" }, + { "svg", "image/svg+xml" }, + }; + + auto it = vMimeTypes.find(rExtension); + return it == vMimeTypes.end() ? OUString() : it->second; +} + +/// Determines the base directory for cover images, XMP metadata, popup images. +OUString FindMediaDir(const OUString& rDocumentBaseURL, + const uno::Sequence<beans::PropertyValue>& rFilterData) +{ + OUString aMediaDir; + + // See if filter data contains a media directory explicitly. + auto pProp = std::find_if( + rFilterData.begin(), rFilterData.end(), + [](const beans::PropertyValue& rProp) { return rProp.Name == "RVNGMediaDir"; }); + if (pProp != rFilterData.end()) + pProp->Value >>= aMediaDir; + + if (!aMediaDir.isEmpty()) + return aMediaDir + "/"; + + // Not set explicitly, try to pick it up from the base directory. + INetURLObject aURL(rDocumentBaseURL); + try + { + aMediaDir = rtl::Uri::convertRelToAbs(rDocumentBaseURL, aURL.GetBase()) + "/"; + } + catch (const rtl::MalformedUriException&) + { + DBG_UNHANDLED_EXCEPTION("writerperfect"); + } + return aMediaDir; +} + +/// Picks up a cover image from the base directory. +OUString FindCoverImage(const OUString& rDocumentBaseURL, OUString& rMimeType, + const uno::Sequence<beans::PropertyValue>& rFilterData) +{ + OUString aRet; + + // See if filter data contains a cover image explicitly. + auto pProp = std::find_if( + rFilterData.begin(), rFilterData.end(), + [](const beans::PropertyValue& rProp) { return rProp.Name == "RVNGCoverImage"; }); + if (pProp != rFilterData.end()) + pProp->Value >>= aRet; + + if (!aRet.isEmpty()) + { + INetURLObject aRetURL(aRet); + rMimeType = GetMimeType(aRetURL.GetFileExtension()); + return aRet; + } + + // Not set explicitly, try to pick it up from the base directory. + if (rDocumentBaseURL.isEmpty()) + return aRet; + + static const std::initializer_list<std::u16string_view> vExtensions + = { u"gif", u"jpg", u"png", u"svg" }; + + OUString aMediaDir = FindMediaDir(rDocumentBaseURL, rFilterData); + for (const auto& rExtension : vExtensions) + { + aRet = aMediaDir + "cover." + rExtension; + if (!aRet.isEmpty()) + { + SvFileStream aStream(aRet, StreamMode::READ); + if (aStream.IsOpen()) + { + rMimeType = GetMimeType(OUString(rExtension)); + // File exists. + return aRet; + } + + aRet.clear(); + } + } + + 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) +{ + // See if filter data contains metadata explicitly. + OUString aValue; + for (const auto& rProp : rFilterData) + { + if (rProp.Name == "RVNGIdentifier") + { + rProp.Value >>= aValue; + if (!aValue.isEmpty()) + rMetaData.insert("dc:identifier", aValue.toUtf8().getStr()); + } + else if (rProp.Name == "RVNGTitle") + { + rProp.Value >>= aValue; + if (!aValue.isEmpty()) + rMetaData.insert("dc:title", aValue.toUtf8().getStr()); + } + else if (rProp.Name == "RVNGInitialCreator") + { + rProp.Value >>= aValue; + if (!aValue.isEmpty()) + rMetaData.insert("meta:initial-creator", aValue.toUtf8().getStr()); + } + else if (rProp.Name == "RVNGLanguage") + { + rProp.Value >>= aValue; + if (!aValue.isEmpty()) + rMetaData.insert("dc:language", aValue.toUtf8().getStr()); + } + else if (rProp.Name == "RVNGDate") + { + rProp.Value >>= aValue; + if (!aValue.isEmpty()) + rMetaData.insert("dc:date", aValue.toUtf8().getStr()); + } + } + + // If not set explicitly, try to pick it up from the base directory. + if (rDocumentBaseURL.isEmpty()) + return; + + OUString aMediaDir = FindMediaDir(rDocumentBaseURL, rFilterData); + OUString aURL = aMediaDir + "metadata.xmp"; + 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(rMetaData)); + xParser->setDocumentHandler(xXMP); + try + { + xParser->parseStream(aInputSource); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("writerperfect", "parseStream() failed"); + return; + } +} + +/// Handler for <office:body>. +class XMLBodyContext : public XMLImportContext +{ +public: + XMLBodyContext(XMLImport& rImport); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const uno::Reference<xml::sax::XAttributeList>& /*xAttribs*/) override; +}; +} + +XMLBodyContext::XMLBodyContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +rtl::Reference<XMLImportContext> +XMLBodyContext::CreateChildContext(const OUString& rName, + const uno::Reference<xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "office:text") + return new XMLBodyContentContext(GetImport()); + return nullptr; +} + +namespace +{ +/// Handler for <office:document>. +class XMLOfficeDocContext : public XMLImportContext +{ +public: + XMLOfficeDocContext(XMLImport& rImport); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const uno::Reference<xml::sax::XAttributeList>& /*xAttribs*/) override; + + // Handles metafile for a single page. + void HandleFixedLayoutPage(const FixedLayoutPage& rPage, bool bFirst); +}; +} + +XMLOfficeDocContext::XMLOfficeDocContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +rtl::Reference<XMLImportContext> XMLOfficeDocContext::CreateChildContext( + const OUString& rName, const uno::Reference<xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "office:meta") + return new XMLMetaDocumentContext(GetImport()); + if (rName == "office:automatic-styles") + return new XMLStylesContext(GetImport(), XMLStylesContext::StyleType_AUTOMATIC); + if (rName == "office:styles") + return new XMLStylesContext(GetImport(), XMLStylesContext::StyleType_NONE); + if (rName == "office:master-styles") + return new XMLStylesContext(GetImport(), XMLStylesContext::StyleType_NONE); + if (rName == "office:font-face-decls") + return new XMLFontFaceDeclsContext(GetImport()); + if (rName == "office:body") + { + if (GetImport().GetPageMetafiles().empty()) + return new XMLBodyContext(GetImport()); + + // Ignore text from doc model in the fixed layout case, instead + // insert the page metafiles. + bool bFirst = true; + for (const auto& rPage : GetImport().GetPageMetafiles()) + { + HandleFixedLayoutPage(rPage, bFirst); + if (bFirst) + bFirst = false; + } + } + return nullptr; +} + +void XMLOfficeDocContext::HandleFixedLayoutPage(const FixedLayoutPage& rPage, bool bFirst) +{ + uno::Reference<uno::XComponentContext> xCtx = GetImport().GetComponentContext(); + uno::Reference<xml::sax::XWriter> xSaxWriter = xml::sax::Writer::create(xCtx); + if (!xSaxWriter.is()) + return; + + // [-loplugin:redundantfcast] false positive: + uno::Sequence<uno::Any> aArguments = { uno::Any(uno::Sequence<beans::PropertyValue>( + { comphelper::makePropertyValue("DTDString", false) })) }; + uno::Reference<svg::XSVGWriter> xSVGWriter( + xCtx->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.svg.SVGWriter", aArguments, xCtx), + uno::UNO_QUERY); + if (!xSVGWriter.is()) + return; + + SvMemoryStream aMemoryStream; + xSaxWriter->setOutputStream(new utl::OStreamWrapper(aMemoryStream)); + + xSVGWriter->write(xSaxWriter, rPage.aMetafile); + + // Have all the info, invoke the generator. + librevenge::RVNGPropertyList aPageProperties; + // Pixel -> inch. + double fWidth = rPage.aCssPixels.getWidth(); + fWidth /= 96; + aPageProperties.insert("fo:page-width", fWidth); + double fHeight = rPage.aCssPixels.getHeight(); + fHeight /= 96; + aPageProperties.insert("fo:page-height", fHeight); + + if (!rPage.aChapterNames.empty()) + { + // Name of chapters starting on this page. + librevenge::RVNGPropertyListVector aChapterNames; + for (const auto& rName : rPage.aChapterNames) + { + librevenge::RVNGPropertyList aChapter; + aChapter.insert("librevenge:name", rName.toUtf8().getStr()); + aChapterNames.append(aChapter); + } + aPageProperties.insert("librevenge:chapter-names", aChapterNames); + } + + GetImport().GetGenerator().openPageSpan(aPageProperties); + librevenge::RVNGPropertyList aParagraphProperties; + if (!bFirst) + // All pages except the first one needs a page break before the page + // metafile. + aParagraphProperties.insert("fo:break-before", "page"); + GetImport().GetGenerator().openParagraph(aParagraphProperties); + librevenge::RVNGPropertyList aImageProperties; + aImageProperties.insert("librevenge:mime-type", "image/svg+xml"); + librevenge::RVNGBinaryData aBinaryData; + aBinaryData.append(static_cast<const unsigned char*>(aMemoryStream.GetData()), + aMemoryStream.GetSize()); + aImageProperties.insert("office:binary-data", aBinaryData); + GetImport().GetGenerator().insertBinaryObject(aImageProperties); + GetImport().GetGenerator().closeParagraph(); + GetImport().GetGenerator().closePageSpan(); +} + +XMLImport::XMLImport(const uno::Reference<uno::XComponentContext>& xContext, + librevenge::RVNGTextInterface& rGenerator, const OUString& rURL, + const uno::Sequence<beans::PropertyValue>& rDescriptor, + const std::vector<FixedLayoutPage>& rPageMetafiles) + : mrGenerator(rGenerator) + , mxContext(xContext) + , mbIsInPageSpan(false) + , mrPageMetafiles(rPageMetafiles) +{ + uno::Sequence<beans::PropertyValue> aFilterData; + auto pDescriptor = std::find_if( + rDescriptor.begin(), rDescriptor.end(), + [](const beans::PropertyValue& rProp) { return rProp.Name == "FilterData"; }); + if (pDescriptor != rDescriptor.end()) + pDescriptor->Value >>= aFilterData; + + maMediaDir = FindMediaDir(rURL, aFilterData); + + OUString aMimeType; + OUString aCoverImage = FindCoverImage(rURL, aMimeType, aFilterData); + if (!aCoverImage.isEmpty()) + { + librevenge::RVNGBinaryData aBinaryData; + SvFileStream aStream(aCoverImage, StreamMode::READ); + SvMemoryStream aMemoryStream; + aMemoryStream.WriteStream(aStream); + aBinaryData.append(static_cast<const unsigned char*>(aMemoryStream.GetData()), + aMemoryStream.GetSize()); + librevenge::RVNGPropertyList aCoverImageProperties; + aCoverImageProperties.insert("office:binary-data", aBinaryData); + aCoverImageProperties.insert("librevenge:mime-type", aMimeType.toUtf8().getStr()); + maCoverImages.append(aCoverImageProperties); + } + + FindXMPMetadata(mxContext, rURL, aFilterData, maMetaData); + + mxUriReferenceFactory = uri::UriReferenceFactory::create(mxContext); +} + +const librevenge::RVNGPropertyListVector& XMLImport::GetCoverImages() const +{ + return maCoverImages; +} + +const librevenge::RVNGPropertyList& XMLImport::GetMetaData() const { return maMetaData; } + +namespace +{ +/// Finds out if a file URL exists. +bool FileURLExists(const OUString& rURL) +{ + SvFileStream aStream(rURL, StreamMode::READ); + return aStream.IsOpen(); +} +} + +PopupState XMLImport::FillPopupData(const OUString& rURL, librevenge::RVNGPropertyList& rPropList) +{ + uno::Reference<uri::XUriReference> xUriRef; + try + { + xUriRef = mxUriReferenceFactory->parse(rURL); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("writerperfect", "XUriReference::parse() failed"); + } + bool bAbsolute = true; + if (xUriRef.is()) + bAbsolute = xUriRef->isAbsolute(); + if (bAbsolute) + return PopupState::NotConsumed; + + // Default case: relative URL, popup data was in the same directory as the + // document at insertion time. + OUString aAbs = maMediaDir + rURL; + if (!FileURLExists(aAbs)) + // Fallback case: relative URL, popup data was in the default media + // directory at insertion time. + aAbs = maMediaDir + "../" + rURL; + + if (!FileURLExists(aAbs)) + // Relative link, but points to non-existing file: don't emit that to + // librevenge, since it will be invalid anyway. + return PopupState::Ignore; + + SvFileStream aStream(aAbs, StreamMode::READ); + librevenge::RVNGBinaryData aBinaryData; + SvMemoryStream aMemoryStream; + aMemoryStream.WriteStream(aStream); + aBinaryData.append(static_cast<const unsigned char*>(aMemoryStream.GetData()), + aMemoryStream.GetSize()); + rPropList.insert("office:binary-data", aBinaryData); + + INetURLObject aAbsURL(aAbs); + OUString aMimeType = GetMimeType(aAbsURL.GetFileExtension()); + rPropList.insert("librevenge:mime-type", aMimeType.toUtf8().getStr()); + + return PopupState::Consumed; +} + +const std::vector<FixedLayoutPage>& XMLImport::GetPageMetafiles() const { return mrPageMetafiles; } + +const uno::Reference<uno::XComponentContext>& XMLImport::GetComponentContext() const +{ + return mxContext; +} + +rtl::Reference<XMLImportContext> +XMLImport::CreateContext(std::u16string_view rName, + const uno::Reference<xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == u"office:document") + return new XMLOfficeDocContext(*this); + return nullptr; +} + +librevenge::RVNGTextInterface& XMLImport::GetGenerator() const { return mrGenerator; } + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetAutomaticTextStyles() +{ + return maAutomaticTextStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetAutomaticParagraphStyles() +{ + return maAutomaticParagraphStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetAutomaticCellStyles() +{ + return maAutomaticCellStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetAutomaticColumnStyles() +{ + return maAutomaticColumnStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetAutomaticRowStyles() +{ + return maAutomaticRowStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetAutomaticTableStyles() +{ + return maAutomaticTableStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetAutomaticGraphicStyles() +{ + return maAutomaticGraphicStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetTextStyles() +{ + return maTextStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetParagraphStyles() +{ + return maParagraphStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetCellStyles() +{ + return maCellStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetColumnStyles() +{ + return maColumnStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetRowStyles() { return maRowStyles; } + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetTableStyles() +{ + return maTableStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetGraphicStyles() +{ + return maGraphicStyles; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetPageLayouts() +{ + return maPageLayouts; +} + +std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetMasterStyles() +{ + return maMasterStyles; +} + +void XMLImport::startDocument() { mrGenerator.startDocument(librevenge::RVNGPropertyList()); } + +void XMLImport::endDocument() { mrGenerator.endDocument(); } + +void XMLImport::startElement(const OUString& rName, + const uno::Reference<xml::sax::XAttributeList>& xAttribs) +{ + rtl::Reference<XMLImportContext> xContext; + if (!maContexts.empty()) + { + if (maContexts.top().is()) + xContext = maContexts.top()->CreateChildContext(rName, xAttribs); + } + else + xContext = CreateContext(rName, xAttribs); + + if (xContext.is()) + xContext->startElement(rName, xAttribs); + + maContexts.push(xContext); +} + +void XMLImport::endElement(const OUString& rName) +{ + if (maContexts.empty()) + return; + + if (maContexts.top().is()) + maContexts.top()->endElement(rName); + + maContexts.pop(); +} + +void XMLImport::characters(const OUString& rChars) +{ + if (maContexts.top().is()) + maContexts.top()->characters(rChars); +} + +void XMLImport::ignorableWhitespace(const OUString& /*rWhitespaces*/) {} + +void XMLImport::processingInstruction(const OUString& /*rTarget*/, const OUString& /*rData*/) {} + +void XMLImport::setDocumentLocator(const uno::Reference<xml::sax::XLocator>& /*xLocator*/) {} + +void XMLImport::HandlePageSpan(const librevenge::RVNGPropertyList& rPropertyList) +{ + OUString sMasterPageName; + OUString sLayoutName; + + if (rPropertyList["style:master-page-name"]) + sMasterPageName = OStringToOUString( + rPropertyList["style:master-page-name"]->getStr().cstr(), RTL_TEXTENCODING_UTF8); + else if (!GetIsInPageSpan()) + sMasterPageName = "Standard"; + + if (sMasterPageName.getLength()) + { + librevenge::RVNGPropertyList& rMasterPage = GetMasterStyles()[sMasterPageName]; + if (rMasterPage["style:page-layout-name"]) + { + sLayoutName = OStringToOUString(rMasterPage["style:page-layout-name"]->getStr().cstr(), + RTL_TEXTENCODING_UTF8); + } + } + + if (sLayoutName.getLength()) + { + librevenge::RVNGPropertyList& rPageLayout = GetPageLayouts()[sLayoutName]; + + if (GetIsInPageSpan()) + GetGenerator().closePageSpan(); + + GetGenerator().openPageSpan(rPageLayout); + mbIsInPageSpan = true; + } +} + +} // namespace writerperfect + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/xmlimp.hxx b/writerperfect/source/writer/exp/xmlimp.hxx new file mode 100644 index 000000000..fd2882371 --- /dev/null +++ b/writerperfect/source/writer/exp/xmlimp.hxx @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <map> +#include <stack> +#include <vector> + +#include <librevenge/librevenge.h> + +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> + +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> +#include <tools/gen.hxx> + +#include "xmlictxt.hxx" + +namespace com::sun::star +{ +namespace beans +{ +struct PropertyValue; +} +namespace uno +{ +class XComponentContext; +} +namespace uri +{ +class XUriReferenceFactory; +} +} + +namespace writerperfect::exp +{ +class XMLImportContext; + +/// Contains info about a fixed-layout page. +struct FixedLayoutPage +{ + css::uno::Sequence<sal_Int8> aMetafile; + Size aCssPixels; + std::vector<OUString> aChapterNames; +}; + +/// States describing the result of a link -> popup conversion. +enum class PopupState +{ + /// Conversion did not happen yet. + NONE, + /// The relative link was converted to a popup. + Consumed, + /// The absolute link was not handled. + NotConsumed, + /// The relative link is invalid and should be ignored. + Ignore +}; + +/// ODT export feeds this class to make librevenge calls. +class XMLImport : public cppu::WeakImplHelper<css::xml::sax::XDocumentHandler> +{ + librevenge::RVNGTextInterface& mrGenerator; + std::stack<rtl::Reference<XMLImportContext>> maContexts; + std::map<OUString, librevenge::RVNGPropertyList> maAutomaticTextStyles; + std::map<OUString, librevenge::RVNGPropertyList> maTextStyles; + std::map<OUString, librevenge::RVNGPropertyList> maAutomaticParagraphStyles; + std::map<OUString, librevenge::RVNGPropertyList> maParagraphStyles; + std::map<OUString, librevenge::RVNGPropertyList> maAutomaticCellStyles; + std::map<OUString, librevenge::RVNGPropertyList> maCellStyles; + std::map<OUString, librevenge::RVNGPropertyList> maAutomaticColumnStyles; + std::map<OUString, librevenge::RVNGPropertyList> maColumnStyles; + std::map<OUString, librevenge::RVNGPropertyList> maAutomaticRowStyles; + std::map<OUString, librevenge::RVNGPropertyList> maRowStyles; + std::map<OUString, librevenge::RVNGPropertyList> maAutomaticTableStyles; + std::map<OUString, librevenge::RVNGPropertyList> maTableStyles; + std::map<OUString, librevenge::RVNGPropertyList> maAutomaticGraphicStyles; + std::map<OUString, librevenge::RVNGPropertyList> maGraphicStyles; + std::map<OUString, librevenge::RVNGPropertyList> maPageLayouts; + std::map<OUString, librevenge::RVNGPropertyList> maMasterStyles; + 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; + css::uno::Reference<css::uri::XUriReferenceFactory> mxUriReferenceFactory; + OUString maMediaDir; + bool mbIsInPageSpan; + const std::vector<FixedLayoutPage>& mrPageMetafiles; + +public: + XMLImport(const css::uno::Reference<css::uno::XComponentContext>& xContext, + librevenge::RVNGTextInterface& rGenerator, const OUString& rURL, + const css::uno::Sequence<css::beans::PropertyValue>& rDescriptor, + const std::vector<FixedLayoutPage>& rPageMetafiles); + + rtl::Reference<XMLImportContext> + CreateContext(std::u16string_view rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs); + + librevenge::RVNGTextInterface& GetGenerator() const; + std::map<OUString, librevenge::RVNGPropertyList>& GetAutomaticTextStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetAutomaticParagraphStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetAutomaticCellStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetAutomaticColumnStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetAutomaticRowStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetAutomaticTableStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetAutomaticGraphicStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetTextStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetParagraphStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetCellStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetColumnStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetRowStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetTableStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetGraphicStyles(); + std::map<OUString, librevenge::RVNGPropertyList>& GetPageLayouts(); + std::map<OUString, librevenge::RVNGPropertyList>& GetMasterStyles(); + const librevenge::RVNGPropertyListVector& GetCoverImages() const; + const librevenge::RVNGPropertyList& GetMetaData() const; + PopupState FillPopupData(const OUString& rURL, librevenge::RVNGPropertyList& rPropList); + const std::vector<FixedLayoutPage>& GetPageMetafiles() const; + const css::uno::Reference<css::uno::XComponentContext>& GetComponentContext() const; + + bool GetIsInPageSpan() const { return mbIsInPageSpan; } + void HandlePageSpan(const librevenge::RVNGPropertyList& rPropertyList); + + // XDocumentHandler + void SAL_CALL startDocument() override; + void SAL_CALL endDocument() override; + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + void SAL_CALL characters(const OUString& rChars) override; + void SAL_CALL ignorableWhitespace(const OUString& rWhitespaces) override; + void SAL_CALL processingInstruction(const OUString& rTarget, const OUString& rData) override; + void SAL_CALL + setDocumentLocator(const css::uno::Reference<css::xml::sax::XLocator>& xLocator) override; +}; + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/xmlmetai.cxx b/writerperfect/source/writer/exp/xmlmetai.cxx new file mode 100644 index 000000000..2e42f740f --- /dev/null +++ b/writerperfect/source/writer/exp/xmlmetai.cxx @@ -0,0 +1,285 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "xmlmetai.hxx" + +#include "xmlimp.hxx" + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +namespace +{ +/// Handler for <dc:title>. +class XMLDcTitleContext : public XMLImportContext +{ +public: + XMLDcTitleContext(XMLImport& rImport, XMLMetaDocumentContext& rMeta); + + void SAL_CALL characters(const OUString& rChars) override; + +private: + XMLMetaDocumentContext& mrMeta; +}; +} + +XMLDcTitleContext::XMLDcTitleContext(XMLImport& rImport, XMLMetaDocumentContext& rMeta) + : XMLImportContext(rImport) + , mrMeta(rMeta) +{ +} + +void XMLDcTitleContext::characters(const OUString& rChars) +{ + OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8); + if (!mrMeta.GetPropertyList()["dc:title"]) + mrMeta.GetPropertyList().insert("dc:title", librevenge::RVNGString(sCharU8.getStr())); +} + +namespace +{ +/// Handler for <dc:language>. +class XMLDcLanguageContext : public XMLImportContext +{ +public: + XMLDcLanguageContext(XMLImport& rImport, XMLMetaDocumentContext& rMeta); + + void SAL_CALL characters(const OUString& rChars) override; + +private: + XMLMetaDocumentContext& mrMeta; +}; +} + +XMLDcLanguageContext::XMLDcLanguageContext(XMLImport& rImport, XMLMetaDocumentContext& rMeta) + : XMLImportContext(rImport) + , mrMeta(rMeta) +{ +} + +void XMLDcLanguageContext::characters(const OUString& rChars) +{ + OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8); + if (!mrMeta.GetPropertyList()["dc:language"]) + mrMeta.GetPropertyList().insert("dc:language", librevenge::RVNGString(sCharU8.getStr())); +} + +namespace +{ +/// Handler for <dc:date>. +class XMLDcDateContext : public XMLImportContext +{ +public: + XMLDcDateContext(XMLImport& rImport, XMLMetaDocumentContext& rMeta); + + void SAL_CALL characters(const OUString& rChars) override; + +private: + XMLMetaDocumentContext& mrMeta; +}; +} + +XMLDcDateContext::XMLDcDateContext(XMLImport& rImport, XMLMetaDocumentContext& rMeta) + : XMLImportContext(rImport) + , mrMeta(rMeta) +{ +} + +void XMLDcDateContext::characters(const OUString& rChars) +{ + OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8); + if (!mrMeta.GetPropertyList()["dc:date"]) + mrMeta.GetPropertyList().insert("dc:date", librevenge::RVNGString(sCharU8.getStr())); +} + +namespace +{ +/// Handler for <meta:generator>. +class XMLMetaGeneratorContext : public XMLImportContext +{ +public: + XMLMetaGeneratorContext(XMLImport& rImport, XMLMetaDocumentContext& rMeta); + + void SAL_CALL characters(const OUString& rChars) override; + +private: + XMLMetaDocumentContext& mrMeta; +}; +} + +XMLMetaGeneratorContext::XMLMetaGeneratorContext(XMLImport& rImport, XMLMetaDocumentContext& rMeta) + : XMLImportContext(rImport) + , mrMeta(rMeta) +{ +} + +void XMLMetaGeneratorContext::characters(const OUString& rChars) +{ + OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8); + mrMeta.GetPropertyList().insert("meta:generator", librevenge::RVNGString(sCharU8.getStr())); +} + +namespace +{ +/// Handler for <meta:initial-creator>. +class XMLMetaInitialCreatorContext : public XMLImportContext +{ +public: + XMLMetaInitialCreatorContext(XMLImport& rImport, XMLMetaDocumentContext& rMeta); + + void SAL_CALL characters(const OUString& rChars) override; + +private: + XMLMetaDocumentContext& mrMeta; +}; +} + +XMLMetaInitialCreatorContext::XMLMetaInitialCreatorContext(XMLImport& rImport, + XMLMetaDocumentContext& rMeta) + : XMLImportContext(rImport) + , mrMeta(rMeta) +{ +} + +void XMLMetaInitialCreatorContext::characters(const OUString& rChars) +{ + OString sCharU8 = OUStringToOString(rChars, RTL_TEXTENCODING_UTF8); + if (!mrMeta.GetPropertyList()["meta:initial-creator"]) + mrMeta.GetPropertyList().insert("meta:initial-creator", + librevenge::RVNGString(sCharU8.getStr())); +} + +XMLMetaDocumentContext::XMLMetaDocumentContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ + librevenge::RVNGPropertyList::Iter it(GetImport().GetMetaData()); + for (it.rewind(); it.next();) + m_aPropertyList.insert(it.key(), it()->clone()); + m_aPropertyList.insert("librevenge:cover-images", GetImport().GetCoverImages()); +} + +rtl::Reference<XMLImportContext> XMLMetaDocumentContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "dc:title") + return new XMLDcTitleContext(GetImport(), *this); + if (rName == "dc:language") + return new XMLDcLanguageContext(GetImport(), *this); + if (rName == "dc:date") + return new XMLDcDateContext(GetImport(), *this); + if (rName == "meta:generator") + return new XMLMetaGeneratorContext(GetImport(), *this); + if (rName == "meta:initial-creator") + return new XMLMetaInitialCreatorContext(GetImport(), *this); + return nullptr; +} + +void XMLMetaDocumentContext::endElement(const OUString& /*rName*/) +{ + GetImport().GetGenerator().setDocumentMetaData(m_aPropertyList); +} + +XMPParser::XMPParser(librevenge::RVNGPropertyList& rMetaData) + : mrMetaData(rMetaData) +{ +} + +XMPParser::~XMPParser() = default; + +void XMPParser::startDocument() {} + +void XMPParser::endDocument() +{ + if (!mrMetaData["dc:identifier"] && !m_aIdentifier.isEmpty()) + mrMetaData.insert("dc:identifier", m_aIdentifier.toUtf8().getStr()); + if (!mrMetaData["dc:title"] && !m_aTitle.isEmpty()) + mrMetaData.insert("dc:title", m_aTitle.toUtf8().getStr()); + if (!mrMetaData["meta:initial-creator"] && !m_aCreator.isEmpty()) + mrMetaData.insert("meta:initial-creator", m_aCreator.toUtf8().getStr()); + if (!mrMetaData["dc:language"] && !m_aLanguage.isEmpty()) + mrMetaData.insert("dc:language", m_aLanguage.toUtf8().getStr()); + if (!mrMetaData["dc:date"] && !m_aDate.isEmpty()) + mrMetaData.insert("dc:date", m_aDate.toUtf8().getStr()); +} + +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 writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/xmlmetai.hxx b/writerperfect/source/writer/exp/xmlmetai.hxx new file mode 100644 index 000000000..f87ddff24 --- /dev/null +++ b/writerperfect/source/writer/exp/xmlmetai.hxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <librevenge/librevenge.h> + +#include "xmlictxt.hxx" + +namespace writerperfect::exp +{ +/// Handler for <office:meta>. +class XMLMetaDocumentContext : public XMLImportContext +{ +public: + XMLMetaDocumentContext(XMLImport& rImport); + + librevenge::RVNGPropertyList& GetPropertyList() { return m_aPropertyList; } + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL endElement(const OUString& rName) override; + +private: + librevenge::RVNGPropertyList m_aPropertyList; +}; + +/// Parses an XMP file. +class XMPParser : public cppu::WeakImplHelper<css::xml::sax::XDocumentHandler> +{ +public: + explicit XMPParser(librevenge::RVNGPropertyList& rMetaData); + ~XMPParser() override; + + // XDocumentHandler + void SAL_CALL startDocument() override; + + void SAL_CALL endDocument() override; + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL endElement(const OUString& rName) override; + + void SAL_CALL characters(const OUString& rChars) override; + + void SAL_CALL ignorableWhitespace(const OUString& aWhitespaces) override; + + void SAL_CALL processingInstruction(const OUString& aTarget, const OUString& aData) override; + + void SAL_CALL + setDocumentLocator(const css::uno::Reference<css::xml::sax::XLocator>& xLocator) override; + +private: + librevenge::RVNGPropertyList& mrMetaData; + bool m_bInIdentifier = false; + OUString m_aIdentifier; + bool m_bInTitle = false; + bool m_bInTitleItem = false; + OUString m_aTitle; + bool m_bInCreator = false; + bool m_bInCreatorItem = false; + OUString m_aCreator; + bool m_bInLanguage = false; + bool m_bInLanguageItem = false; + OUString m_aLanguage; + bool m_bInDate = false; + bool m_bInDateItem = false; + OUString m_aDate; +}; + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/xmltbli.cxx b/writerperfect/source/writer/exp/xmltbli.cxx new file mode 100644 index 000000000..0e5818f0b --- /dev/null +++ b/writerperfect/source/writer/exp/xmltbli.cxx @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "xmltbli.hxx" + +#include "txtparai.hxx" +#include "xmlimp.hxx" +#include "xmltext.hxx" + +#include <sal/log.hxx> + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +namespace +{ +/// Handler for <table:table-row>. +class XMLTableRowContext : public XMLImportContext +{ +public: + XMLTableRowContext(XMLImport& rImport); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + int GetColumn() const; + void SetColumn(int nColumn); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + +private: + int m_nColumn = 0; +}; + +/// Handler for <table:cell>. +class XMLTableCellContext : public XMLImportContext +{ +public: + XMLTableCellContext(XMLImport& rImport, XMLTableRowContext& rRow); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + +private: + XMLTableRowContext& m_rRow; +}; +} + +XMLTableCellContext::XMLTableCellContext(XMLImport& rImport, XMLTableRowContext& rRow) + : XMLImportContext(rImport) + , m_rRow(rRow) +{ +} + +rtl::Reference<XMLImportContext> XMLTableCellContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + return CreateTextChildContext(GetImport(), rName); +} + +void XMLTableCellContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + librevenge::RVNGPropertyList aPropertyList; + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + + if (rAttributeName == "table:style-name") + FillStyles(rAttributeValue, GetImport().GetAutomaticCellStyles(), + GetImport().GetCellStyles(), aPropertyList); + else + { + OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + aPropertyList.insert(sName.getStr(), sValue.getStr()); + } + } + aPropertyList.insert("librevenge:column", m_rRow.GetColumn()); + GetImport().GetGenerator().openTableCell(aPropertyList); + m_rRow.SetColumn(m_rRow.GetColumn() + 1); +} + +void XMLTableCellContext::endElement(const OUString& /*rName*/) +{ + GetImport().GetGenerator().closeTableCell(); +} + +namespace +{ +/// Handler for <table:table-column>. +class XMLTableColumnContext : public XMLImportContext +{ +public: + XMLTableColumnContext(XMLImport& rImport, librevenge::RVNGPropertyListVector& rColumns); + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + +private: + librevenge::RVNGPropertyListVector& m_rColumns; +}; +} + +XMLTableColumnContext::XMLTableColumnContext(XMLImport& rImport, + librevenge::RVNGPropertyListVector& rColumns) + : XMLImportContext(rImport) + , m_rColumns(rColumns) +{ +} + +void XMLTableColumnContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + librevenge::RVNGPropertyList aPropertyList; + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + + if (rAttributeName == "table:style-name") + FillStyles(rAttributeValue, GetImport().GetAutomaticColumnStyles(), + GetImport().GetColumnStyles(), aPropertyList); + } + m_rColumns.append(aPropertyList); +} + +XMLTableRowContext::XMLTableRowContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +rtl::Reference<XMLImportContext> XMLTableRowContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "table:table-cell") + return new XMLTableCellContext(GetImport(), *this); + if (rName == "table:covered-table-cell") + { + ++m_nColumn; + GetImport().GetGenerator().insertCoveredTableCell(librevenge::RVNGPropertyList()); + } + else + SAL_WARN("writerperfect", "XMLTableRowContext::CreateChildContext: unhandled " << rName); + return nullptr; +} + +void XMLTableRowContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + librevenge::RVNGPropertyList aPropertyList; + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + + if (rAttributeName == "table:style-name") + FillStyles(rAttributeValue, GetImport().GetAutomaticRowStyles(), + GetImport().GetRowStyles(), aPropertyList); + } + GetImport().GetGenerator().openTableRow(aPropertyList); +} + +void XMLTableRowContext::endElement(const OUString& /*rName*/) +{ + GetImport().GetGenerator().closeTableRow(); +} + +int XMLTableRowContext::GetColumn() const { return m_nColumn; } + +void XMLTableRowContext::SetColumn(int nColumn) { m_nColumn = nColumn; } + +XMLTableContext::XMLTableContext(XMLImport& rImport, bool bTopLevel) + : XMLImportContext(rImport) + , m_bTopLevel(bTopLevel) +{ +} + +rtl::Reference<XMLImportContext> XMLTableContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + if (rName == "table:table-column") + // Make sure columns are parsed before we open the table. + return new XMLTableColumnContext(GetImport(), m_aColumns); + + if (!m_bTableOpened) + { + if (!m_aColumns.empty()) + m_aPropertyList.insert("librevenge:table-columns", m_aColumns); + GetImport().GetGenerator().openTable(m_aPropertyList); + m_bTableOpened = true; + } + + if (rName == "table:table-row") + return new XMLTableRowContext(GetImport()); + + SAL_WARN("writerperfect", "XMLTableContext::CreateChildContext: unhandled " << rName); + + return nullptr; +} + +void XMLTableContext::startElement( + const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) +{ + for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i) + { + const OUString& rAttributeName = xAttribs->getNameByIndex(i); + const OUString& rAttributeValue = xAttribs->getValueByIndex(i); + + if (rAttributeName == "table:style-name") + { + FillStyles(rAttributeValue, GetImport().GetAutomaticTableStyles(), + GetImport().GetTableStyles(), m_aPropertyList); + if (m_bTopLevel) + GetImport().HandlePageSpan(m_aPropertyList); + } + else + { + OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8); + OString sValue = OUStringToOString(rAttributeValue, RTL_TEXTENCODING_UTF8); + m_aPropertyList.insert(sName.getStr(), sValue.getStr()); + } + } +} + +void XMLTableContext::endElement(const OUString& /*rName*/) +{ + if (m_bTableOpened) + { + GetImport().GetGenerator().closeTable(); + } +} + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/xmltbli.hxx b/writerperfect/source/writer/exp/xmltbli.hxx new file mode 100644 index 000000000..c1b33f498 --- /dev/null +++ b/writerperfect/source/writer/exp/xmltbli.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <librevenge/librevenge.h> + +#include "xmlictxt.hxx" + +namespace writerperfect::exp +{ +/// Handler for <table:table>. +class XMLTableContext : public XMLImportContext +{ +public: + XMLTableContext(XMLImport& rImport, bool bTopLevel = false); + + rtl::Reference<XMLImportContext> + CreateChildContext(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + + void SAL_CALL + startElement(const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override; + void SAL_CALL endElement(const OUString& rName) override; + +private: + bool m_bTableOpened = false; + /// If the context is a direct child of XMLBodyContentContext. + /// Only direct child of XMLBodyContentContext has to handle page span. + bool m_bTopLevel; + librevenge::RVNGPropertyList m_aPropertyList; + librevenge::RVNGPropertyListVector m_aColumns; +}; + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/xmltext.cxx b/writerperfect/source/writer/exp/xmltext.cxx new file mode 100644 index 000000000..933cf43e1 --- /dev/null +++ b/writerperfect/source/writer/exp/xmltext.cxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "xmltext.hxx" + +#include "txtparai.hxx" +#include "xmltbli.hxx" +#include "XMLSectionContext.hxx" +#include "XMLTextListContext.hxx" +#include "xmlimp.hxx" + +using namespace com::sun::star; + +namespace writerperfect::exp +{ +XMLBodyContentContext::XMLBodyContentContext(XMLImport& rImport) + : XMLImportContext(rImport) +{ +} + +void XMLBodyContentContext::endElement(const OUString& /*rName*/) +{ + if (GetImport().GetIsInPageSpan()) + GetImport().GetGenerator().closePageSpan(); +} + +rtl::Reference<XMLImportContext> XMLBodyContentContext::CreateChildContext( + const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) +{ + return CreateTextChildContext(GetImport(), rName, true); +} + +rtl::Reference<XMLImportContext> CreateTextChildContext(XMLImport& rImport, + std::u16string_view rName, bool bTopLevel) +{ + if (rName == u"text:p" || rName == u"text:h") + return new XMLParaContext(rImport, bTopLevel); + if (rName == u"text:section") + return new XMLSectionContext(rImport); + if (rName == u"table:table") + return new XMLTableContext(rImport, bTopLevel); + if (rName == u"text:list") + return new XMLTextListContext(rImport); + return nullptr; +} + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/exp/xmltext.hxx b/writerperfect/source/writer/exp/xmltext.hxx new file mode 100644 index 000000000..50188acfe --- /dev/null +++ b/writerperfect/source/writer/exp/xmltext.hxx @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "xmlictxt.hxx" + +namespace writerperfect::exp +{ +/// Handler for <office:text>. +class XMLBodyContentContext : public XMLImportContext +{ +public: + XMLBodyContentContext(XMLImport& rImport); + + rtl::Reference<XMLImportContext> CreateChildContext( + const OUString& rName, + const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) override; + void SAL_CALL endElement(const OUString& rName) override; +}; + +/// Context factory for body text, section, table cell, etc. +rtl::Reference<XMLImportContext> +CreateTextChildContext(XMLImport& rImport, std::u16string_view rName, bool bTopLevel = false); + +} // namespace writerperfect::exp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/writer/wpftwriter.component b/writerperfect/source/writer/wpftwriter.component new file mode 100644 index 000000000..176d48750 --- /dev/null +++ b/writerperfect/source/writer/wpftwriter.component @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . +--> +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.Writer.AbiWordImportFilter" + constructor="com_sun_star_comp_Writer_AbiWordImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + <optional/> + </implementation> + <implementation name="com.sun.star.comp.Writer.MSWorksImportFilter" + constructor="com_sun_star_comp_Writer_MSWorksImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + <optional/> + </implementation> + <implementation name="com.sun.star.comp.Writer.MWAWImportFilter" + constructor="com_sun_star_comp_Writer_MWAWImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + <optional/> + </implementation> + <implementation name="com.sun.star.comp.Writer.WordPerfectImportFilter" + constructor="com_sun_star_comp_Writer_WordPerfectImportFilter_get_implementation"> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + <service name="com.sun.star.document.ImportFilter"/> + <optional/> + </implementation> + <implementation name="org.libreoffice.comp.Writer.EBookImportFilter" + constructor="org_libreoffice_comp_Writer_EBookImportFilter_get_implementation"> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + <service name="com.sun.star.document.ImportFilter"/> + <optional/> + </implementation> + <implementation name="org.libreoffice.comp.Writer.PagesImportFilter" + constructor="org_libreoffice_comp_Writer_PagesImportFilter_get_implementation"> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + <service name="com.sun.star.document.ImportFilter"/> + <optional/> + </implementation> + <implementation name="org.libreoffice.comp.Writer.StarOfficeWriterImportFilter" + constructor="org_libreoffice_comp_Writer_StarOfficeWriterImportFilter_get_implementation"> + <service name="com.sun.star.document.ImportFilter"/> + <service name="com.sun.star.document.ExtendedTypeDetection"/> + </implementation> + <implementation name="com.sun.star.comp.Writer.EPUBExportFilter" + constructor="com_sun_star_comp_Writer_EPUBExportFilter_get_implementation"> + <service name="com.sun.star.document.ExportFilter"/> + <optional/> + </implementation> + <implementation name="com.sun.star.comp.Writer.EPUBExportUIComponent" + constructor="com_sun_star_comp_Writer_EPUBExportUIComponent_get_implementation"> + <service name="com.sun.star.ui.dialogs.FilterOptionsDialog"/> + <optional/> + </implementation> +</component> diff --git a/writerperfect/source/writer/wpftwriter.component.extended b/writerperfect/source/writer/wpftwriter.component.extended new file mode 100644 index 000000000..577d05e96 --- /dev/null +++ b/writerperfect/source/writer/wpftwriter.component.extended @@ -0,0 +1,8 @@ +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +com.sun.star.comp.Writer.EPUBExportFilter +com.sun.star.comp.Writer.EPUBExportUIComponent diff --git a/writerperfect/source/writer/wpftwriter.component.extended2 b/writerperfect/source/writer/wpftwriter.component.extended2 new file mode 100644 index 000000000..91cd0e046 --- /dev/null +++ b/writerperfect/source/writer/wpftwriter.component.extended2 @@ -0,0 +1,12 @@ +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +com.sun.star.comp.Writer.AbiWordImportFilter +com.sun.star.comp.Writer.MSWorksImportFilter +com.sun.star.comp.Writer.MWAWImportFilter +com.sun.star.comp.Writer.WordPerfectImportFilter +org.libreoffice.comp.Writer.EBookImportFilter +org.libreoffice.comp.Writer.PagesImportFilter |