LibreOffice Module filter (master) 1
XmlFilterAdaptor.cxx
Go to the documentation of this file.
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#include <iostream>
21#include <rtl/ustring.hxx>
22#include <sal/log.hxx>
24#include <tools/urlobj.hxx>
25#include "XmlFilterAdaptor.hxx"
26#include <com/sun/star/io/XActiveDataSource.hpp>
27#include <com/sun/star/xml/XImportFilter.hpp>
28#include <com/sun/star/xml/XImportFilter2.hpp>
29#include <com/sun/star/xml/XExportFilter.hpp>
30#include <com/sun/star/task/XStatusIndicator.hpp>
31#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
32#include <com/sun/star/style/XStyleLoader.hpp>
33#include <com/sun/star/frame/XModel.hpp>
37#include <com/sun/star/beans/PropertyAttribute.hpp>
38#include <com/sun/star/beans/XPropertySet.hpp>
44#include <xmloff/xmlimp.hxx>
45
46#include <strings.hrc>
47
48using namespace comphelper;
49using namespace com::sun::star::uno;
50using namespace com::sun::star::lang;
51using namespace com::sun::star::io;
52using namespace com::sun::star::beans;
53using namespace com::sun::star::container;
54using namespace com::sun::star::document;
55using namespace com::sun::star::style;
56using namespace com::sun::star::xml;
57using namespace com::sun::star::xml::sax;
58using namespace com::sun::star::frame;
59using namespace ::com::sun::star::task;
60
62{
63 OUString udConvertClass = msUserData[0];
64 const OUString sXMLImportService = msUserData[2];
65 sal_Int32 nSteps= 0;
66
67 utl::MediaDescriptor aMediaMap(aDescriptor);
68 Reference< XStatusIndicator > xStatusIndicator(aMediaMap.getUnpackedValueOrDefault(
70
71 if (xStatusIndicator.is()){
72 xStatusIndicator->start(FilterResId(STR_FILTER_DOC_LOADING), 4);
73 }
74
75 OUString aBaseURI;
76 if (aMediaMap.find(OUString( "URL" ))->second >>= aBaseURI)
77 {
78 INetURLObject aURLObj(aBaseURI);
79 // base URI in this case is the URI of the actual saving location
80 // aURLObj.removeSegment();
82 }
83
84 // create an XProperty set to configure the exporter for pretty printing
85 static const PropertyMapEntry aImportInfoMap[] =
86 {
87 { OUString("BaseURI"), 0, ::cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0},
88 { OUString("BuildId"), 0, ::cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0 },
89 { OUString("DefaultDocumentSettings"), 0,
90 ::cppu::UnoType<Sequence<PropertyValue>>::get(), PropertyAttribute::MAYBEVOID, 0 },
91 };
92
94 GenericPropertySet_CreateInstance( new PropertySetInfo( aImportInfoMap ) ) );
95 xInfoSet->setPropertyValue( "BaseURI", Any( aBaseURI ));
96
97 OUString aFilterName;
98 auto It = aMediaMap.find(OUString("FilterName"));
99 if (It != aMediaMap.end() && (It->second >>= aFilterName)
100 && aFilterName == "OpenDocument Text Flat XML")
101 {
102 PropertyValue EmptyDbFieldHidesPara("EmptyDbFieldHidesPara", 0, Any(false),
103 PropertyState::PropertyState_DIRECT_VALUE);
104 Sequence<PropertyValue> aSettings{ EmptyDbFieldHidesPara };
105 xInfoSet->setPropertyValue("DefaultDocumentSettings", Any(aSettings));
106 }
107 Sequence< Any > aAnys{ Any(xInfoSet) };
108
109
110 // the underlying SvXMLImport implements XFastParser, XImporter, XFastDocumentHandler
111 // ...except when it's one of the XMLTransformer subclasses
112 Reference < XInterface > xFilter = mxContext->getServiceManager()->createInstanceWithArgumentsAndContext( sXMLImportService, aAnys, mxContext );
113 assert(xFilter);
114 Reference < XImporter > xImporter( xFilter, UNO_QUERY );
115 assert(xImporter);
116 xImporter->setTargetDocument ( mxDoc );
117
118 if (xStatusIndicator.is()){
119 xStatusIndicator->setValue(nSteps++);
120 }
121
122
123 // Creating a ConverterBridge instance
124
125 Reference< XInterface > xConvBridge(
126 mxContext->getServiceManager()->createInstanceWithContext(udConvertClass, mxContext), UNO_QUERY);
127 if (!xConvBridge.is()) {
128 SAL_WARN("filter.xmlfa", "XmlFilterAdaptor: unable to create service " << udConvertClass);
129 return false;
130 }
131 if (xStatusIndicator.is())
132 xStatusIndicator->setValue(nSteps++);
133
134 Reference< XImportFilter > xConverter1( xConvBridge, UNO_QUERY );
135 Reference< XImportFilter2 > xConverter2( xConvBridge, UNO_QUERY );
136
137 // prevent unnecessary broadcasting when loading
138 Reference< XModel > xModel( mxDoc, UNO_QUERY );
139 if( xModel.is() )
140 xModel->lockControllers();
141 comphelper::ScopeGuard guard([&]() {
142 // cleanup when leaving
143 if( xModel.is() )
144 xModel->unlockControllers();
145 });
146
147 //Template Loading if Required
148
149 if (!msTemplateName.isEmpty()){
150 Reference< XStyleFamiliesSupplier > xstylefamiliessupplier(mxDoc, UNO_QUERY);
151 Reference< XStyleLoader > xstyleLoader (xstylefamiliessupplier->getStyleFamilies(), UNO_QUERY);
152 if(xstyleLoader.is()){
153 Sequence<css::beans::PropertyValue> aValue = xstyleLoader->getStyleLoaderOptions();
154
155 //Load the Styles from the Template URL Supplied in the TypeDetection file
157 {
158 SvtPathOptions aOptions;
159 msTemplateName = aOptions.SubstituteVariable("$(progurl)") + "/" + msTemplateName;
160 }
161
162 xstyleLoader->loadStylesFromURL(msTemplateName,aValue);
163 }
164 }
165
166 if (xStatusIndicator.is()){
167 xStatusIndicator->setValue(nSteps++);
168 }
169
170 // Calling Filtering Component
171
172 try {
173 Reference < XFastParser > xFastParser( xFilter, UNO_QUERY ); // SvXMLImport subclasses
174 Reference < XDocumentHandler > xDocHandler( xFilter, UNO_QUERY ); // XMLTransformer subclasses
175 assert(xFastParser || xDocHandler);
176 if (xConverter2 && xFastParser)
177 {
178 if (!xConverter2->importer(aDescriptor,xFastParser,msUserData)) {
179 if (xStatusIndicator.is())
180 xStatusIndicator->end();
181 return false;
182 }
183 }
184 else if (xConverter1 && xDocHandler)
185 {
186 if (!xConverter1->importer(aDescriptor,xDocHandler,msUserData)) {
187 if (xStatusIndicator.is())
188 xStatusIndicator->end();
189 return false;
190 }
191 }
192 else if (xConverter1 && xFastParser)
193 {
194 auto pImport = static_cast<SvXMLImport*>(xFastParser.get());
195 Reference<XDocumentHandler> xLegacyDocHandler = new SvXMLLegacyToFastDocHandler(pImport);
196 if (!xConverter1->importer(aDescriptor,xLegacyDocHandler,msUserData)) {
197 if (xStatusIndicator.is())
198 xStatusIndicator->end();
199 return false;
200 }
201 }
202 else
203 {
204 SAL_WARN("filter.xmlfa", "no working combination found");
205 assert(false);
206 if (xStatusIndicator.is())
207 xStatusIndicator->end();
208 return false;
209 }
210 }
211 catch( const Exception& )
212 {
213 TOOLS_WARN_EXCEPTION("filter.xmlfa", "XmlFilterAdaptor");
214 if (xStatusIndicator.is())
215 xStatusIndicator->end();
216 return false;
217 }
218 if (xStatusIndicator.is()) {
219 xStatusIndicator->setValue(nSteps++);
220 xStatusIndicator->end();
221 }
222 return true;
223}
224
226{
227
228 OUString udConvertClass = msUserData[0];
229 OUString udExport = msUserData[3];
230
231 // Status Bar
232 sal_Int32 nSteps= 1;
233 utl::MediaDescriptor aMediaMap(aDescriptor);
234 Reference< XStatusIndicator > xStatusIndicator(aMediaMap.getUnpackedValueOrDefault(
236
237 if (xStatusIndicator.is())
238 xStatusIndicator->start(FilterResId(STR_FILTER_DOC_SAVING), 3);
239
240 // Set up converter bridge.
241 Reference< css::xml::XExportFilter > xConverter(mxContext->getServiceManager()->createInstanceWithContext( udConvertClass, mxContext ), UNO_QUERY);
242 if (!xConverter.is()) {
243 SAL_WARN("filter.xmlfa", "XmlFilterAdaptor: unable to create service " << udConvertClass);
244 return false;
245 }
246
247 if (xStatusIndicator.is())
248 xStatusIndicator->setValue(nSteps++);
249
250 //put filter component into exporting state
251 if (!xConverter->exporter(aDescriptor, msUserData)) {
252 if (xStatusIndicator.is())
253 xStatusIndicator->end();
254 return false;
255 }
256 if (xStatusIndicator.is())
257 xStatusIndicator->setValue(nSteps++);
258
259 try{
260 // create the xml exporter service and supply the converter component
261 // which implements the document handler
262
263 // pretty printing is confusing for some filters so it is disabled by default
264 bool bPrettyPrint =
265 (msUserData.getLength() > 6 && msUserData[6].equalsIgnoreAsciiCase("true"));
266
267 // export of <text:number> element for <text:list-item> elements are
268 // needed for certain filters.
269 bool bExportTextNumberElementForListItems =
270 ( msUserData.getLength() > 7 &&
271 msUserData[7].equalsIgnoreAsciiCase("true") );
272
273 // get the base URI, so we can use relative links
274 OUString aBaseURI;
275 if (aMediaMap.find(OUString( "URL" ))->second >>= aBaseURI)
276 {
277 INetURLObject aURLObj(aBaseURI);
278 // base URI in this case is the URI of the actual saving location
279 // aURLObj.removeSegment();
281 }
282
283 // create an XProperty set to configure the exporter for pretty printing
284 static const PropertyMapEntry aImportInfoMap[] =
285 {
286 { OUString("UsePrettyPrinting"), 0, cppu::UnoType<sal_Bool>::get(), PropertyAttribute::MAYBEVOID, 0},
287 { OUString("ExportTextNumberElement"), 0, cppu::UnoType<sal_Bool>::get(), PropertyAttribute::MAYBEVOID, 0},
288 { OUString("BaseURI"), 0, ::cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0},
289 };
290
292 GenericPropertySet_CreateInstance( new PropertySetInfo( aImportInfoMap ) ) );
293 xInfoSet->setPropertyValue("UsePrettyPrinting", Any( bPrettyPrint ));
294 xInfoSet->setPropertyValue(
295 "ExportTextNumberElement",
296 Any( bExportTextNumberElementForListItems ));
297 xInfoSet->setPropertyValue("BaseURI", Any( aBaseURI ));
298 Sequence < Any > aAnys{ Any(xConverter), Any(xInfoSet) };
299
300 Reference< XExporter > xExporter( mxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
301 udExport, aAnys, mxContext ), UNO_QUERY_THROW );
302
303 // attach to source document
304 xExporter->setSourceDocument( mxDoc );
305
306 // get XFilter interface
307 Reference< XFilter > xFilter( xExporter, UNO_QUERY_THROW );
308
309 if (xStatusIndicator.is())
310 xStatusIndicator->setValue(nSteps++);
311
312 // call the actual filtering component
313 if (!xFilter->filter(aDescriptor))
314 {
315 if (xStatusIndicator.is())
316 xStatusIndicator->end();
317 return false;
318 }
319 }
320 catch (const Exception&)
321 {
322 TOOLS_WARN_EXCEPTION("filter.xmlfa", "XmlFilterAdaptor");
323 if (xStatusIndicator.is())
324 xStatusIndicator->end();
325 return false;
326 }
327
328 // done
329 if (xStatusIndicator.is())
330 xStatusIndicator->end();
331 return true;
332}
333
335{
336 return meType == FILTER_EXPORT ? exportImpl ( aDescriptor ) : importImpl ( aDescriptor );
337}
339{
340}
341// XExporter
343{
345 mxDoc = xDoc;
346}
347
348// XImporter
350{
352 mxDoc = xDoc;
353}
354// XInitialization
355void SAL_CALL XmlFilterAdaptor::initialize( const Sequence< Any >& aArguments )
356{
358 if ( aArguments.hasElements() && ( aArguments[0] >>= aAnySeq ) )
359 {
361 msFilterName = aMap.getUnpackedValueOrDefault(
362 "Type", OUString());
363 msUserData = aMap.getUnpackedValueOrDefault(
364 "UserData", Sequence< OUString >());
365 msTemplateName = aMap.getUnpackedValueOrDefault(
366 "TemplateName", OUString());
367 }
368}
369
370// XServiceInfo
372{
373 return "com.sun.star.comp.Writer.XmlFilterAdaptor";
374}
375
376sal_Bool SAL_CALL XmlFilterAdaptor::supportsService( const OUString& rServiceName )
377{
378 return cppu::supportsService( this, rServiceName );
379}
380
382{
383 return { "com.sun.star.document.ExportFilter", "com.sun.star.document.ImportFilter" };
384}
385
386extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
388 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
389{
390 return cppu::acquire(new XmlFilterAdaptor(context));
391}
392
393/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * filter_XmlFilterAdaptor_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
@ FILTER_IMPORT
@ FILTER_EXPORT
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString SubstituteVariable(const OUString &rVar) const
virtual void SAL_CALL cancel() override
bool exportImpl(const css::uno::Sequence< css::beans::PropertyValue > &aDescriptor)
bool importImpl(const css::uno::Sequence< css::beans::PropertyValue > &aDescriptor)
virtual sal_Bool SAL_CALL filter(const css::uno::Sequence< css::beans::PropertyValue > &aDescriptor) override
virtual void SAL_CALL setTargetDocument(const css::uno::Reference< css::lang::XComponent > &xDoc) override
css::uno::Reference< css::lang::XComponent > mxDoc
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
css::uno::Reference< css::uno::XComponentContext > mxContext
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual OUString SAL_CALL getImplementationName() override
css::uno::Sequence< OUString > msUserData
virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > &aArguments) override
virtual void SAL_CALL setSourceDocument(const css::uno::Reference< css::lang::XComponent > &xDoc) override
css::uno::Type const & get()
static constexpr OUStringLiteral PROP_STATUSINDICATOR
#define TOOLS_WARN_EXCEPTION(area, stream)
Reference< XTypeConverter > xConverter
Sequence< PropertyValue > aArguments
#define SAL_WARN(area, stream)
@ Exception
COMPHELPER_DLLPUBLIC bool isFileUrl(std::u16string_view url)
COMPHELPER_DLLPUBLIC css::uno::Reference< css::beans::XPropertySet > GenericPropertySet_CreateInstance(PropertySetInfo *pInfo)
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
HashMap_OWString_Interface aMap
Reference< XModel > xModel
unsigned char sal_Bool