Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #ifdef DEBUG_WRITERFILTER
21 : #include <iostream>
22 : #endif
23 :
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/lang/WrappedTargetRuntimeException.hpp>
30 : #include <com/sun/star/lang/XInitialization.hpp>
31 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 : #include <com/sun/star/xml/sax/SAXParseException.hpp>
33 : #include <cppuhelper/exc_hlp.hxx>
34 : #include <cppuhelper/implbase.hxx>
35 : #include <cppuhelper/supportsservice.hxx>
36 : #include <dmapper/DomainMapperFactory.hxx>
37 : #include <oox/core/filterdetect.hxx>
38 : #include <oox/helper/graphichelper.hxx>
39 : #include <oox/ole/olestorage.hxx>
40 : #include <oox/ole/vbaproject.hxx>
41 : #include <ooxml/OOXMLDocument.hxx>
42 : #include <unotools/mediadescriptor.hxx>
43 :
44 : using namespace ::com::sun::star;
45 :
46 : static OUString lcl_GetExceptionMessageRec(xml::sax::SAXException const& e);
47 :
48 0 : static OUString lcl_GetExceptionMessage(xml::sax::SAXException const& e)
49 : {
50 0 : OUString const thisMessage("SAXParseException: \"" + e.Message + "\"");
51 0 : OUString const restMessage(lcl_GetExceptionMessageRec(e));
52 0 : return restMessage + "\n" + thisMessage;
53 : }
54 1 : static OUString lcl_GetExceptionMessage(xml::sax::SAXParseException const& e)
55 : {
56 2 : OUString const thisMessage("SAXParseException: '" + e.Message + "', Stream '" + e.SystemId + "', Line " + OUString::number(e.LineNumber)
57 3 : + ", Column " + OUString::number(e.ColumnNumber));
58 2 : OUString const restMessage(lcl_GetExceptionMessageRec(e));
59 2 : return restMessage + "\n" + thisMessage;
60 : }
61 :
62 1 : static OUString lcl_GetExceptionMessageRec(xml::sax::SAXException const& e)
63 : {
64 1 : xml::sax::SAXParseException saxpe;
65 1 : if (e.WrappedException >>= saxpe)
66 : {
67 0 : return lcl_GetExceptionMessage(saxpe);
68 : }
69 2 : xml::sax::SAXException saxe;
70 1 : if (e.WrappedException >>= saxe)
71 : {
72 0 : return lcl_GetExceptionMessage(saxe);
73 : }
74 2 : uno::Exception ue;
75 1 : if (e.WrappedException >>= ue)
76 : {
77 0 : return ue.Message;
78 : }
79 2 : return OUString();
80 : }
81 :
82 : /// Common DOCX filter, calls DocxExportFilter via UNO or does the DOCX import.
83 : class WriterFilter : public cppu::WeakImplHelper
84 : <
85 : document::XFilter,
86 : document::XImporter,
87 : document::XExporter,
88 : lang::XInitialization,
89 : lang::XServiceInfo
90 : >
91 : {
92 :
93 : protected:
94 : uno::Reference<uno::XComponentContext> m_xContext;
95 : uno::Reference<lang::XComponent> m_xSrcDoc, m_xDstDoc;
96 :
97 : public:
98 2007 : explicit WriterFilter(const uno::Reference<uno::XComponentContext>& rxContext)
99 2007 : : m_xContext(rxContext)
100 2007 : {}
101 4014 : virtual ~WriterFilter() {}
102 :
103 : // XFilter
104 : virtual sal_Bool SAL_CALL filter(const uno::Sequence<beans::PropertyValue>& rDescriptor) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
105 : virtual void SAL_CALL cancel() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
106 :
107 : // XImporter
108 : virtual void SAL_CALL setTargetDocument(const uno::Reference<lang::XComponent>& xDoc) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE;
109 :
110 : // XExporter
111 : virtual void SAL_CALL setSourceDocument(const uno::Reference<lang::XComponent>& xDoc) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE;
112 :
113 : // XInitialization
114 : virtual void SAL_CALL initialize(const uno::Sequence<uno::Any>& rArguments) throw (uno::Exception, uno::RuntimeException, std::exception) SAL_OVERRIDE;
115 :
116 : // XServiceInfo
117 : virtual OUString SAL_CALL getImplementationName() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
118 : virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
119 : virtual uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
120 :
121 : private:
122 : void putPropertiesToDocumentGrabBag(const comphelper::SequenceAsHashMap& rProperties);
123 :
124 : };
125 :
126 2006 : sal_Bool WriterFilter::filter(const uno::Sequence< beans::PropertyValue >& aDescriptor) throw (uno::RuntimeException, std::exception)
127 : {
128 2006 : if (m_xSrcDoc.is())
129 : {
130 482 : uno::Reference< lang::XMultiServiceFactory > xMSF(m_xContext->getServiceManager(), uno::UNO_QUERY_THROW);
131 964 : uno::Reference< uno::XInterface > xIfc;
132 : try
133 : {
134 482 : xIfc.set(xMSF->createInstance("com.sun.star.comp.Writer.DocxExport"), uno::UNO_QUERY_THROW);
135 : }
136 0 : catch (uno::RuntimeException&)
137 : {
138 0 : throw;
139 : }
140 0 : catch (uno::Exception& e)
141 : {
142 0 : uno::Any a(cppu::getCaughtException());
143 0 : throw lang::WrappedTargetRuntimeException("wrapped " + a.getValueTypeName() + ": " + e.Message, uno::Reference<uno::XInterface>(), a);
144 : }
145 964 : uno::Reference< document::XExporter > xExprtr(xIfc, uno::UNO_QUERY_THROW);
146 964 : uno::Reference< document::XFilter > xFltr(xIfc, uno::UNO_QUERY_THROW);
147 482 : if (!xExprtr.is() || !xFltr.is())
148 0 : return sal_False;
149 482 : xExprtr->setSourceDocument(m_xSrcDoc);
150 964 : return xFltr->filter(aDescriptor);
151 : }
152 1524 : else if (m_xDstDoc.is())
153 : {
154 1524 : utl::MediaDescriptor aMediaDesc(aDescriptor);
155 1524 : bool bRepairStorage = aMediaDesc.getUnpackedValueOrDefault("RepairPackage", false);
156 1524 : bool bSkipImages = aMediaDesc.getUnpackedValueOrDefault("FilterOptions", OUString("")) == "SkipImages";
157 :
158 3048 : uno::Reference< io::XInputStream > xInputStream;
159 : try
160 : {
161 : // use the oox.core.FilterDetect implementation to extract the decrypted ZIP package
162 1524 : ::oox::core::FilterDetect aDetector(m_xContext);
163 1524 : xInputStream = aDetector.extractUnencryptedPackage(aMediaDesc);
164 : }
165 0 : catch (uno::Exception&)
166 : {
167 : }
168 :
169 1524 : if (!xInputStream.is())
170 0 : return sal_False;
171 :
172 1524 : writerfilter::dmapper::SourceDocumentType eType = writerfilter::dmapper::SourceDocumentType::OOXML;
173 : writerfilter::Stream::Pointer_t pStream(
174 3048 : writerfilter::dmapper::DomainMapperFactory::createMapper(m_xContext, xInputStream, m_xDstDoc, bRepairStorage, eType, uno::Reference<text::XTextRange>(), aMediaDesc));
175 : //create the tokenizer and domain mapper
176 3048 : writerfilter::ooxml::OOXMLStream::Pointer_t pDocStream = writerfilter::ooxml::OOXMLDocumentFactory::createStream(m_xContext, xInputStream, bRepairStorage);
177 3048 : uno::Reference<task::XStatusIndicator> xStatusIndicator = aMediaDesc.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_STATUSINDICATOR(), uno::Reference<task::XStatusIndicator>());
178 3048 : writerfilter::ooxml::OOXMLDocument::Pointer_t pDocument(writerfilter::ooxml::OOXMLDocumentFactory::createDocument(pDocStream, xStatusIndicator, bSkipImages));
179 :
180 3048 : uno::Reference<frame::XModel> xModel(m_xDstDoc, uno::UNO_QUERY_THROW);
181 1524 : pDocument->setModel(xModel);
182 :
183 : uno::Reference<drawing::XDrawPageSupplier> xDrawings
184 3048 : (m_xDstDoc, uno::UNO_QUERY_THROW);
185 : uno::Reference<drawing::XDrawPage> xDrawPage
186 3048 : (xDrawings->getDrawPage(), uno::UNO_SET_THROW);
187 1524 : pDocument->setDrawPage(xDrawPage);
188 :
189 : try
190 : {
191 1524 : pDocument->resolve(*pStream);
192 : }
193 2 : catch (xml::sax::SAXParseException const& e)
194 : {
195 : // note: SfxObjectShell checks for WrongFormatException
196 1 : io::WrongFormatException wfe(lcl_GetExceptionMessage(e));
197 : throw lang::WrappedTargetRuntimeException("",
198 1 : static_cast<OWeakObject*>(this), uno::makeAny(wfe));
199 : }
200 0 : catch (xml::sax::SAXException const& e)
201 : {
202 : // note: SfxObjectShell checks for WrongFormatException
203 0 : io::WrongFormatException wfe(lcl_GetExceptionMessage(e));
204 : throw lang::WrappedTargetRuntimeException("",
205 0 : static_cast<OWeakObject*>(this), uno::makeAny(wfe));
206 : }
207 0 : catch (uno::RuntimeException const&)
208 : {
209 0 : throw;
210 : }
211 2 : catch (uno::Exception const& e)
212 : {
213 : SAL_WARN("writerfilter", "WriterFilter::filter(): "
214 : "failed with exception " << e.Message);
215 : throw lang::WrappedTargetRuntimeException("",
216 1 : static_cast<OWeakObject*>(this), uno::makeAny(e));
217 : }
218 :
219 : // Adding some properties to the document's grab bag for interoperability purposes:
220 3044 : comphelper::SequenceAsHashMap aGrabBagProperties;
221 :
222 : // Adding the saved Theme DOM
223 1522 : aGrabBagProperties["OOXTheme"] = uno::makeAny(pDocument->getThemeDom());
224 :
225 : // Adding the saved custom xml DOM
226 1522 : aGrabBagProperties["OOXCustomXml"] = uno::makeAny(pDocument->getCustomXmlDomList());
227 1522 : aGrabBagProperties["OOXCustomXmlProps"] = uno::makeAny(pDocument->getCustomXmlDomPropsList());
228 :
229 : // Adding the saved ActiveX DOM
230 1522 : aGrabBagProperties["OOXActiveX"] = uno::makeAny(pDocument->getActiveXDomList());
231 1522 : aGrabBagProperties["OOXActiveXBin"] = uno::makeAny(pDocument->getActiveXBinList());
232 :
233 : // Adding the saved Glossary Documnet DOM to the document's grab bag
234 1522 : aGrabBagProperties["OOXGlossary"] = uno::makeAny(pDocument->getGlossaryDocDom());
235 1522 : aGrabBagProperties["OOXGlossaryDom"] = uno::makeAny(pDocument->getGlossaryDomList());
236 :
237 : // Adding the saved embedding document to document's grab bag
238 1522 : aGrabBagProperties["OOXEmbeddings"] = uno::makeAny(pDocument->getEmbeddingsList());
239 :
240 1522 : putPropertiesToDocumentGrabBag(aGrabBagProperties);
241 :
242 3044 : writerfilter::ooxml::OOXMLStream::Pointer_t pVBAProjectStream(writerfilter::ooxml::OOXMLDocumentFactory::createStream(pDocStream, writerfilter::ooxml::OOXMLStream::VBAPROJECT));
243 3044 : oox::StorageRef xVbaPrjStrg(new ::oox::ole::OleStorage(m_xContext, pVBAProjectStream->getDocumentStream(), false));
244 1522 : if (xVbaPrjStrg.get() && xVbaPrjStrg->isStorage())
245 : {
246 0 : ::oox::ole::VbaProject aVbaProject(m_xContext, xModel, "Writer");
247 0 : uno::Reference< frame::XFrame > xFrame = aMediaDesc.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FRAME(), uno::Reference< frame::XFrame > ());
248 :
249 : // if no XFrame try fallback to what we can glean from the Model
250 0 : if (!xFrame.is())
251 : {
252 0 : uno::Reference< frame::XController > xController = xModel->getCurrentController();
253 0 : xFrame = xController.is() ? xController->getFrame() : nullptr;
254 : }
255 :
256 0 : oox::GraphicHelper gHelper(m_xContext, xFrame, xVbaPrjStrg);
257 0 : aVbaProject.importVbaProject(*xVbaPrjStrg, gHelper);
258 : }
259 :
260 : // Document signature.
261 3044 : writerfilter::ooxml::OOXMLStream::Pointer_t pSignatureStream;
262 1522 : pSignatureStream = writerfilter::ooxml::OOXMLDocumentFactory::createStream(m_xContext, xInputStream, bRepairStorage, writerfilter::ooxml::OOXMLStream::SIGNATURE);
263 1522 : if (pSignatureStream->getDocumentStream().is())
264 : {
265 : // TODO found, handle it.
266 : }
267 :
268 1522 : pStream.reset();
269 :
270 3046 : return sal_True;
271 : }
272 0 : return sal_False;
273 : }
274 :
275 :
276 0 : void WriterFilter::cancel() throw (uno::RuntimeException, std::exception)
277 : {
278 0 : }
279 :
280 1524 : void WriterFilter::setTargetDocument(const uno::Reference< lang::XComponent >& xDoc) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
281 : {
282 1524 : m_xDstDoc = xDoc;
283 :
284 : // Set some compatibility options that are valid for all the formats
285 1524 : uno::Reference< lang::XMultiServiceFactory > xFactory(xDoc, uno::UNO_QUERY);
286 3048 : uno::Reference< beans::XPropertySet > xSettings(xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
287 :
288 1524 : xSettings->setPropertyValue("AddFrameOffsets", uno::makeAny(sal_True));
289 1524 : xSettings->setPropertyValue("UseOldNumbering", uno::makeAny(sal_False));
290 1524 : xSettings->setPropertyValue("IgnoreFirstLineIndentInNumbering", uno::makeAny(sal_False));
291 1524 : xSettings->setPropertyValue("DoNotResetParaAttrsForNumFont", uno::makeAny(sal_False));
292 1524 : xSettings->setPropertyValue("UseFormerLineSpacing", uno::makeAny(sal_False));
293 1524 : xSettings->setPropertyValue("AddParaSpacingToTableCells", uno::makeAny(sal_True));
294 1524 : xSettings->setPropertyValue("UseFormerObjectPositioning", uno::makeAny(sal_False));
295 1524 : xSettings->setPropertyValue("ConsiderTextWrapOnObjPos", uno::makeAny(sal_True));
296 1524 : xSettings->setPropertyValue("UseFormerTextWrapping", uno::makeAny(sal_False));
297 1524 : xSettings->setPropertyValue("TableRowKeep", uno::makeAny(sal_True));
298 1524 : xSettings->setPropertyValue("IgnoreTabsAndBlanksForLineCalculation", uno::makeAny(sal_True));
299 1524 : xSettings->setPropertyValue("InvertBorderSpacing", uno::makeAny(sal_True));
300 1524 : xSettings->setPropertyValue("CollapseEmptyCellPara", uno::makeAny(sal_True));
301 1524 : xSettings->setPropertyValue("TabOverflow", uno::makeAny(sal_True));
302 1524 : xSettings->setPropertyValue("UnbreakableNumberings", uno::makeAny(sal_True));
303 :
304 1524 : xSettings->setPropertyValue("FloattableNomargins", uno::makeAny(sal_True));
305 1524 : xSettings->setPropertyValue("ClippedPictures", uno::makeAny(sal_True));
306 1524 : xSettings->setPropertyValue("BackgroundParaOverDrawings", uno::makeAny(sal_True));
307 1524 : xSettings->setPropertyValue("TabOverMargin", uno::makeAny(sal_True));
308 3048 : xSettings->setPropertyValue("PropLineSpacingShrinksFirstLine", uno::makeAny(sal_True));
309 1524 : }
310 :
311 482 : void WriterFilter::setSourceDocument(const uno::Reference< lang::XComponent >& xDoc) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
312 : {
313 482 : m_xSrcDoc = xDoc;
314 482 : }
315 :
316 2001 : void WriterFilter::initialize(const uno::Sequence< uno::Any >& /*rArguments*/) throw (uno::Exception, uno::RuntimeException, std::exception)
317 : {
318 2001 : }
319 :
320 1 : OUString WriterFilter::getImplementationName() throw (uno::RuntimeException, std::exception)
321 : {
322 1 : return OUString("com.sun.star.comp.Writer.WriterFilter");
323 : }
324 :
325 :
326 0 : sal_Bool WriterFilter::supportsService(const OUString& rServiceName) throw (uno::RuntimeException, std::exception)
327 : {
328 0 : return cppu::supportsService(this, rServiceName);
329 : }
330 :
331 :
332 1 : uno::Sequence<OUString> WriterFilter::getSupportedServiceNames() throw (uno::RuntimeException, std::exception)
333 : {
334 : uno::Sequence<OUString> aRet =
335 : {
336 : OUString("com.sun.star.document.ImportFilter"),
337 : OUString("com.sun.star.document.ExportFilter")
338 1 : };
339 1 : return aRet;
340 : }
341 :
342 1522 : void WriterFilter::putPropertiesToDocumentGrabBag(const comphelper::SequenceAsHashMap& rProperties)
343 : {
344 : try
345 : {
346 1522 : uno::Reference<beans::XPropertySet> xDocProps(m_xDstDoc, uno::UNO_QUERY);
347 1522 : if (xDocProps.is())
348 : {
349 1522 : uno::Reference<beans::XPropertySetInfo> xPropsInfo = xDocProps->getPropertySetInfo();
350 :
351 3044 : const OUString aGrabBagPropName = "InteropGrabBag";
352 1522 : if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(aGrabBagPropName))
353 : {
354 : // get existing grab bag
355 1522 : comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue(aGrabBagPropName));
356 :
357 : // put the new items
358 1522 : aGrabBag.update(rProperties);
359 :
360 : // put it back to the document
361 1522 : xDocProps->setPropertyValue(aGrabBagPropName, uno::Any(aGrabBag.getAsConstPropertyValueList()));
362 1522 : }
363 1522 : }
364 : }
365 0 : catch (const uno::Exception&)
366 : {
367 : SAL_WARN("writerfilter","Failed to save documents grab bag");
368 : }
369 1522 : }
370 :
371 2007 : extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* SAL_CALL com_sun_star_comp_Writer_WriterFilter_get_implementation(uno::XComponentContext* component, uno::Sequence<uno::Any> const&)
372 : {
373 2007 : return cppu::acquire(new WriterFilter(component));
374 72 : }
375 :
376 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|