summaryrefslogtreecommitdiffstats
path: root/writerperfect/source/writer
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /writerperfect/source/writer
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.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/writer')
-rw-r--r--writerperfect/source/writer/AbiWordImportFilter.cxx58
-rw-r--r--writerperfect/source/writer/AbiWordImportFilter.hxx40
-rw-r--r--writerperfect/source/writer/EBookImportFilter.cxx114
-rw-r--r--writerperfect/source/writer/EBookImportFilter.hxx44
-rw-r--r--writerperfect/source/writer/EPUBExportDialog.cxx224
-rw-r--r--writerperfect/source/writer/EPUBExportDialog.hxx61
-rw-r--r--writerperfect/source/writer/EPUBExportFilter.cxx206
-rw-r--r--writerperfect/source/writer/EPUBExportFilter.hxx71
-rw-r--r--writerperfect/source/writer/EPUBExportUIComponent.cxx102
-rw-r--r--writerperfect/source/writer/EPUBExportUIComponent.hxx72
-rw-r--r--writerperfect/source/writer/EPUBPackage.cxx215
-rw-r--r--writerperfect/source/writer/EPUBPackage.hxx90
-rw-r--r--writerperfect/source/writer/MSWorksImportFilter.cxx157
-rw-r--r--writerperfect/source/writer/MSWorksImportFilter.hxx41
-rw-r--r--writerperfect/source/writer/MWAWImportFilter.cxx117
-rw-r--r--writerperfect/source/writer/MWAWImportFilter.hxx41
-rw-r--r--writerperfect/source/writer/PagesImportFilter.cxx63
-rw-r--r--writerperfect/source/writer/PagesImportFilter.hxx40
-rw-r--r--writerperfect/source/writer/StarOfficeWriterImportFilter.cxx128
-rw-r--r--writerperfect/source/writer/StarOfficeWriterImportFilter.hxx42
-rw-r--r--writerperfect/source/writer/WordPerfectImportFilter.cxx238
-rw-r--r--writerperfect/source/writer/WordPerfectImportFilter.hxx63
-rw-r--r--writerperfect/source/writer/exp/XMLBase64ImportContext.cxx65
-rw-r--r--writerperfect/source/writer/exp/XMLBase64ImportContext.hxx42
-rw-r--r--writerperfect/source/writer/exp/XMLFootnoteImportContext.cxx126
-rw-r--r--writerperfect/source/writer/exp/XMLFootnoteImportContext.hxx40
-rw-r--r--writerperfect/source/writer/exp/XMLSectionContext.cxx44
-rw-r--r--writerperfect/source/writer/exp/XMLSectionContext.hxx33
-rw-r--r--writerperfect/source/writer/exp/XMLTextFrameContext.cxx171
-rw-r--r--writerperfect/source/writer/exp/XMLTextFrameContext.hxx38
-rw-r--r--writerperfect/source/writer/exp/XMLTextListContext.cxx33
-rw-r--r--writerperfect/source/writer/exp/XMLTextListContext.hxx29
-rw-r--r--writerperfect/source/writer/exp/XMLTextListItemContext.cxx36
-rw-r--r--writerperfect/source/writer/exp/XMLTextListItemContext.hxx29
-rw-r--r--writerperfect/source/writer/exp/txtparai.cxx634
-rw-r--r--writerperfect/source/writer/exp/txtparai.hxx59
-rw-r--r--writerperfect/source/writer/exp/txtstyli.cxx415
-rw-r--r--writerperfect/source/writer/exp/txtstyli.hxx60
-rw-r--r--writerperfect/source/writer/exp/xmlfmt.cxx295
-rw-r--r--writerperfect/source/writer/exp/xmlfmt.hxx73
-rw-r--r--writerperfect/source/writer/exp/xmlictxt.cxx56
-rw-r--r--writerperfect/source/writer/exp/xmlictxt.hxx51
-rw-r--r--writerperfect/source/writer/exp/xmlimp.cxx621
-rw-r--r--writerperfect/source/writer/exp/xmlimp.hxx149
-rw-r--r--writerperfect/source/writer/exp/xmlmetai.cxx285
-rw-r--r--writerperfect/source/writer/exp/xmlmetai.hxx83
-rw-r--r--writerperfect/source/writer/exp/xmltbli.cxx254
-rw-r--r--writerperfect/source/writer/exp/xmltbli.hxx44
-rw-r--r--writerperfect/source/writer/exp/xmltext.cxx55
-rw-r--r--writerperfect/source/writer/exp/xmltext.hxx34
-rw-r--r--writerperfect/source/writer/wpftwriter.component72
-rw-r--r--writerperfect/source/writer/wpftwriter.component.extended8
-rw-r--r--writerperfect/source/writer/wpftwriter.component.extended212
53 files changed, 6173 insertions, 0 deletions
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