1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/document/XExporter.hpp>
26 #include <com/sun/star/document/XFilter.hpp>
27 #include <com/sun/star/document/XImporter.hpp>
28 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
29 #include <com/sun/star/io/WrongFormatException.hpp>
30 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
31 #include <com/sun/star/lang/XInitialization.hpp>
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/xml/sax/SAXParseException.hpp>
34 #include <cppuhelper/exc_hlp.hxx>
35 #include <cppuhelper/supportsservice.hxx>
36 #include <dmapper/DomainMapperFactory.hxx>
37 #include <oox/core/filterdetect.hxx>
38 #include <oox/core/xmlfilterbase.hxx>
39 #include <oox/helper/graphichelper.hxx>
40 #include <oox/ole/olestorage.hxx>
41 #include <oox/ole/vbaproject.hxx>
42 #include <ooxml/OOXMLDocument.hxx>
43 #include <unotools/mediadescriptor.hxx>
44 #include <rtl/ref.hxx>
45 #include <sal/log.hxx>
46 #include <comphelper/diagnose_ex.hxx>
47 #include <comphelper/scopeguard.hxx>
49 using namespace ::com::sun::star
;
51 static OUString
lcl_GetExceptionMessageRec(xml::sax::SAXException
const& e
);
53 static OUString
lcl_GetExceptionMessage(xml::sax::SAXException
const& e
)
55 OUString
const thisMessage("SAXParseException: \"" + e
.Message
+ "\"");
56 OUString
const restMessage(lcl_GetExceptionMessageRec(e
));
57 return restMessage
+ "\n" + thisMessage
;
59 static OUString
lcl_GetExceptionMessage(xml::sax::SAXParseException
const& e
)
61 OUString
const thisMessage("SAXParseException: '" + e
.Message
+ "', Stream '" + e
.SystemId
62 + "', Line " + OUString::number(e
.LineNumber
) + ", Column "
63 + OUString::number(e
.ColumnNumber
));
64 OUString
const restMessage(lcl_GetExceptionMessageRec(e
));
65 return restMessage
+ "\n" + thisMessage
;
68 static OUString
lcl_GetExceptionMessageRec(xml::sax::SAXException
const& e
)
70 xml::sax::SAXParseException saxpe
;
71 if (e
.WrappedException
>>= saxpe
)
73 return lcl_GetExceptionMessage(saxpe
);
75 xml::sax::SAXException saxe
;
76 if (e
.WrappedException
>>= saxe
)
78 return lcl_GetExceptionMessage(saxe
);
81 if (e
.WrappedException
>>= ue
)
90 /// Common DOCX filter, calls DocxExportFilter via UNO or does the DOCX import.
92 : public cppu::WeakImplHelper
<document::XFilter
, document::XImporter
, document::XExporter
,
93 lang::XInitialization
, lang::XServiceInfo
>
95 uno::Reference
<uno::XComponentContext
> m_xContext
;
96 uno::Reference
<lang::XComponent
> m_xSrcDoc
, m_xDstDoc
;
97 uno::Sequence
<uno::Any
> m_xInitializationArguments
;
100 explicit WriterFilter(uno::Reference
<uno::XComponentContext
> xContext
)
101 : m_xContext(std::move(xContext
))
106 sal_Bool SAL_CALL
filter(const uno::Sequence
<beans::PropertyValue
>& rDescriptor
) override
;
107 void SAL_CALL
cancel() override
;
110 void SAL_CALL
setTargetDocument(const uno::Reference
<lang::XComponent
>& xDoc
) override
;
113 void SAL_CALL
setSourceDocument(const uno::Reference
<lang::XComponent
>& xDoc
) override
;
116 void SAL_CALL
initialize(const uno::Sequence
<uno::Any
>& rArguments
) override
;
119 OUString SAL_CALL
getImplementationName() override
;
120 sal_Bool SAL_CALL
supportsService(const OUString
& rServiceName
) override
;
121 uno::Sequence
<OUString
> SAL_CALL
getSupportedServiceNames() override
;
125 sal_Bool
WriterFilter::filter(const uno::Sequence
<beans::PropertyValue
>& rDescriptor
)
129 uno::Reference
<lang::XMultiServiceFactory
> xMSF(m_xContext
->getServiceManager(),
130 uno::UNO_QUERY_THROW
);
131 uno::Reference
<uno::XInterface
> xIfc
;
134 xIfc
.set(xMSF
->createInstance("com.sun.star.comp.Writer.DocxExport"),
137 catch (uno::RuntimeException
&)
141 catch (uno::Exception
& e
)
143 uno::Any
a(cppu::getCaughtException());
144 throw lang::WrappedTargetRuntimeException("wrapped " + a
.getValueTypeName() + ": "
146 uno::Reference
<uno::XInterface
>(), a
);
149 uno::Reference
<lang::XInitialization
> xInit(xIfc
, uno::UNO_QUERY_THROW
);
150 xInit
->initialize(m_xInitializationArguments
);
152 uno::Reference
<document::XExporter
> xExprtr(xIfc
, uno::UNO_QUERY_THROW
);
153 uno::Reference
<document::XFilter
> xFltr(xIfc
, uno::UNO_QUERY_THROW
);
154 xExprtr
->setSourceDocument(m_xSrcDoc
);
155 return xFltr
->filter(rDescriptor
);
159 uno::Reference
<beans::XPropertySet
> const xDocProps(m_xDstDoc
, uno::UNO_QUERY
);
160 xDocProps
->setPropertyValue("UndocumentedWriterfilterHack", uno::Any(true));
161 comphelper::ScopeGuard
g([xDocProps
] {
162 xDocProps
->setPropertyValue("UndocumentedWriterfilterHack", uno::Any(false));
164 utl::MediaDescriptor
aMediaDesc(rDescriptor
);
165 bool bRepairStorage
= aMediaDesc
.getUnpackedValueOrDefault("RepairPackage", false);
167 = aMediaDesc
.getUnpackedValueOrDefault("FilterOptions", OUString()) == "SkipImages";
169 uno::Reference
<io::XInputStream
> xInputStream
;
172 // use the oox.core.FilterDetect implementation to extract the decrypted ZIP package
173 rtl::Reference
<::oox::core::FilterDetect
> xDetector(
174 new ::oox::core::FilterDetect(m_xContext
));
175 xInputStream
= xDetector
->extractUnencryptedPackage(aMediaDesc
);
177 catch (uno::Exception
&)
181 if (!xInputStream
.is())
184 writerfilter::Stream::Pointer_t
pStream(
185 writerfilter::dmapper::DomainMapperFactory::createMapper(
186 m_xContext
, xInputStream
, m_xDstDoc
, bRepairStorage
,
187 writerfilter::dmapper::SourceDocumentType::OOXML
, aMediaDesc
));
188 //create the tokenizer and domain mapper
189 writerfilter::ooxml::OOXMLStream::Pointer_t pDocStream
190 = writerfilter::ooxml::OOXMLDocumentFactory::createStream(m_xContext
, xInputStream
,
192 uno::Reference
<task::XStatusIndicator
> xStatusIndicator
193 = aMediaDesc
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_STATUSINDICATOR
,
194 uno::Reference
<task::XStatusIndicator
>());
195 writerfilter::ooxml::OOXMLDocument::Pointer_t
pDocument(
196 writerfilter::ooxml::OOXMLDocumentFactory::createDocument(pDocStream
, xStatusIndicator
,
197 bSkipImages
, rDescriptor
));
199 uno::Reference
<frame::XModel
> xModel(m_xDstDoc
, uno::UNO_QUERY_THROW
);
200 pDocument
->setModel(xModel
);
202 uno::Reference
<drawing::XDrawPageSupplier
> xDrawings(m_xDstDoc
, uno::UNO_QUERY_THROW
);
203 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawings
->getDrawPage(), uno::UNO_SET_THROW
);
204 pDocument
->setDrawPage(xDrawPage
);
208 pDocument
->resolve(*pStream
);
210 catch (xml::sax::SAXParseException
const& e
)
212 // note: SfxObjectShell checks for WrongFormatException
213 io::WrongFormatException
wfe(lcl_GetExceptionMessage(e
));
214 throw lang::WrappedTargetRuntimeException("", getXWeak(), uno::Any(wfe
));
216 catch (xml::sax::SAXException
const& e
)
218 // note: SfxObjectShell checks for WrongFormatException
219 io::WrongFormatException
wfe(lcl_GetExceptionMessage(e
));
220 throw lang::WrappedTargetRuntimeException("", getXWeak(), uno::Any(wfe
));
222 catch (uno::RuntimeException
const&)
226 catch (uno::Exception
const&)
228 css::uno::Any anyEx
= cppu::getCaughtException();
229 SAL_WARN("writerfilter",
230 "WriterFilter::filter(): failed with " << exceptionToString(anyEx
));
231 throw lang::WrappedTargetRuntimeException("", getXWeak(), anyEx
);
234 // Adding some properties to the document's grab bag for interoperability purposes:
235 comphelper::SequenceAsHashMap aGrabBagProperties
;
237 // Adding the saved Theme DOM
238 aGrabBagProperties
["OOXTheme"] <<= pDocument
->getThemeDom();
240 // Adding the saved custom xml DOM
241 aGrabBagProperties
["OOXCustomXml"] <<= pDocument
->getCustomXmlDomList();
242 aGrabBagProperties
["OOXCustomXmlProps"] <<= pDocument
->getCustomXmlDomPropsList();
244 // Adding the saved Glossary Document DOM to the document's grab bag
245 aGrabBagProperties
["OOXGlossary"] <<= pDocument
->getGlossaryDocDom();
246 aGrabBagProperties
["OOXGlossaryDom"] <<= pDocument
->getGlossaryDomList();
248 // Adding the saved embedding document to document's grab bag
249 aGrabBagProperties
["OOXEmbeddings"] <<= pDocument
->getEmbeddingsList();
251 oox::core::XmlFilterBase::putPropertiesToDocumentGrabBag(m_xDstDoc
, aGrabBagProperties
);
253 writerfilter::ooxml::OOXMLStream::Pointer_t
pVBAProjectStream(
254 writerfilter::ooxml::OOXMLDocumentFactory::createStream(
255 pDocStream
, writerfilter::ooxml::OOXMLStream::VBAPROJECT
));
256 oox::StorageRef xVbaPrjStrg
= std::make_shared
<::oox::ole::OleStorage
>(
257 m_xContext
, pVBAProjectStream
->getDocumentStream(), false);
258 if (xVbaPrjStrg
&& xVbaPrjStrg
->isStorage())
260 ::oox::ole::VbaProject
aVbaProject(m_xContext
, xModel
, u
"Writer");
261 uno::Reference
<frame::XFrame
> xFrame
= aMediaDesc
.getUnpackedValueOrDefault(
262 utl::MediaDescriptor::PROP_FRAME
, uno::Reference
<frame::XFrame
>());
264 // if no XFrame try fallback to what we can glean from the Model
267 uno::Reference
<frame::XController
> xController
= xModel
->getCurrentController();
268 xFrame
= xController
.is() ? xController
->getFrame() : nullptr;
271 oox::GraphicHelper
gHelper(m_xContext
, xFrame
, xVbaPrjStrg
);
272 aVbaProject
.importVbaProject(*xVbaPrjStrg
, gHelper
);
274 writerfilter::ooxml::OOXMLStream::Pointer_t
pVBADataStream(
275 writerfilter::ooxml::OOXMLDocumentFactory::createStream(
276 pDocStream
, writerfilter::ooxml::OOXMLStream::VBADATA
));
279 uno::Reference
<io::XInputStream
> xDataStream
= pVBADataStream
->getDocumentStream();
280 if (xDataStream
.is())
281 aVbaProject
.importVbaData(xDataStream
);
287 // note: pStream.clear calls RemoveLastParagraph()
294 void WriterFilter::cancel() {}
296 void WriterFilter::setTargetDocument(const uno::Reference
<lang::XComponent
>& xDoc
)
300 // Set some compatibility options that are valid for the DOCX format
301 uno::Reference
<lang::XMultiServiceFactory
> xFactory(xDoc
, uno::UNO_QUERY
);
302 uno::Reference
<beans::XPropertySet
> xSettings(
303 xFactory
->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY
);
305 xSettings
->setPropertyValue("UseOldNumbering", uno::Any(false));
306 xSettings
->setPropertyValue("IgnoreFirstLineIndentInNumbering", uno::Any(false));
307 xSettings
->setPropertyValue(u
"NoGapAfterNoteNumber"_ustr
, uno::Any(true));
308 xSettings
->setPropertyValue("DoNotResetParaAttrsForNumFont", uno::Any(false));
309 xSettings
->setPropertyValue("UseFormerLineSpacing", uno::Any(false));
310 xSettings
->setPropertyValue("AddParaSpacingToTableCells", uno::Any(true));
311 xSettings
->setPropertyValue("AddParaLineSpacingToTableCells", uno::Any(true));
312 xSettings
->setPropertyValue("UseFormerObjectPositioning", uno::Any(false));
313 xSettings
->setPropertyValue("ConsiderTextWrapOnObjPos", uno::Any(true));
314 xSettings
->setPropertyValue("UseFormerTextWrapping", uno::Any(false));
315 xSettings
->setPropertyValue("IgnoreTabsAndBlanksForLineCalculation", uno::Any(true));
316 xSettings
->setPropertyValue("InvertBorderSpacing", uno::Any(true));
317 xSettings
->setPropertyValue("CollapseEmptyCellPara", uno::Any(true));
318 // tdf#142404 TabOverSpacing (new for compatibilityMode15/Word2013+) is a subset of TabOverMargin
319 // (which applied to DOCX <= compatibilityMode14).
320 // TabOverMargin looks at tabs beyond the normal text area,
321 // while TabOverSpacing only refers to a tab beyond the paragraph margin.
322 xSettings
->setPropertyValue("TabOverSpacing", uno::Any(true));
323 xSettings
->setPropertyValue("UnbreakableNumberings", uno::Any(true));
325 xSettings
->setPropertyValue("ClippedPictures", uno::Any(true));
326 xSettings
->setPropertyValue("BackgroundParaOverDrawings", uno::Any(true));
327 xSettings
->setPropertyValue("TreatSingleColumnBreakAsPageBreak", uno::Any(true));
328 xSettings
->setPropertyValue("PropLineSpacingShrinksFirstLine", uno::Any(true));
329 xSettings
->setPropertyValue("DoNotCaptureDrawObjsOnPage", uno::Any(true));
330 xSettings
->setPropertyValue("DisableOffPagePositioning", uno::Any(true));
331 xSettings
->setPropertyValue("DropCapPunctuation", uno::Any(true));
332 // rely on default for HyphenateURLs=false
333 // rely on default for APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH=true
334 xSettings
->setPropertyValue("DoNotMirrorRtlDrawObjs", uno::Any(true));
335 xSettings
->setPropertyValue("ContinuousEndnotes", uno::Any(true));
338 void WriterFilter::setSourceDocument(const uno::Reference
<lang::XComponent
>& xDoc
)
343 void WriterFilter::initialize(const uno::Sequence
<uno::Any
>& rArguments
)
345 m_xInitializationArguments
= rArguments
;
348 OUString
WriterFilter::getImplementationName() { return "com.sun.star.comp.Writer.WriterFilter"; }
350 sal_Bool
WriterFilter::supportsService(const OUString
& rServiceName
)
352 return cppu::supportsService(this, rServiceName
);
355 uno::Sequence
<OUString
> WriterFilter::getSupportedServiceNames()
357 uno::Sequence
<OUString
> aRet
= { OUString("com.sun.star.document.ImportFilter"),
358 OUString("com.sun.star.document.ExportFilter") };
362 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
363 com_sun_star_comp_Writer_WriterFilter_get_implementation(
364 uno::XComponentContext
* component
, uno::Sequence
<uno::Any
> const& /*rSequence*/)
366 return cppu::acquire(new WriterFilter(component
));
369 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */