/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include "XmlFilterAdaptor.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace comphelper; using namespace com::sun::star::uno; using namespace com::sun::star::lang; using namespace com::sun::star::io; using namespace com::sun::star::beans; using namespace com::sun::star::container; using namespace com::sun::star::document; using namespace com::sun::star::style; using namespace com::sun::star::xml; using namespace com::sun::star::xml::sax; using namespace com::sun::star::frame; using namespace ::com::sun::star::task; bool XmlFilterAdaptor::importImpl( const Sequence< css::beans::PropertyValue >& aDescriptor ) { OUString udConvertClass = msUserData[0]; const OUString sXMLImportService = msUserData[2]; sal_Int32 nSteps= 0; utl::MediaDescriptor aMediaMap(aDescriptor); Reference< XStatusIndicator > xStatusIndicator(aMediaMap.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_STATUSINDICATOR, Reference< XStatusIndicator >())); if (xStatusIndicator.is()){ xStatusIndicator->start( "Loading :", 4); } OUString aBaseURI; if (aMediaMap.find(OUString( "URL" ))->second >>= aBaseURI) { INetURLObject aURLObj(aBaseURI); // base URI in this case is the URI of the actual saving location // aURLObj.removeSegment(); aBaseURI = aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE); } // create an XProperty set to configure the exporter for pretty printing static const PropertyMapEntry aImportInfoMap[] = { { OUString("BaseURI"), 0, ::cppu::UnoType::get(), PropertyAttribute::MAYBEVOID, 0}, { OUString("BuildId"), 0, ::cppu::UnoType::get(), PropertyAttribute::MAYBEVOID, 0 }, { OUString("DefaultDocumentSettings"), 0, ::cppu::UnoType>::get(), PropertyAttribute::MAYBEVOID, 0 }, }; Reference< XPropertySet > xInfoSet( GenericPropertySet_CreateInstance( new PropertySetInfo( aImportInfoMap ) ) ); xInfoSet->setPropertyValue( "BaseURI", Any( aBaseURI )); OUString aFilterName; auto It = aMediaMap.find(OUString("FilterName")); if (It != aMediaMap.end() && (It->second >>= aFilterName) && aFilterName == "OpenDocument Text Flat XML") { PropertyValue EmptyDbFieldHidesPara("EmptyDbFieldHidesPara", 0, Any(false), PropertyState::PropertyState_DIRECT_VALUE); Sequence aSettings{ EmptyDbFieldHidesPara }; xInfoSet->setPropertyValue("DefaultDocumentSettings", Any(aSettings)); } Sequence< Any > aAnys{ Any(xInfoSet) }; // the underlying SvXMLImport implements XFastParser, XImporter, XFastDocumentHandler // ...except when it's one of the XMLTransformer subclasses Reference < XInterface > xFilter = mxContext->getServiceManager()->createInstanceWithArgumentsAndContext( sXMLImportService, aAnys, mxContext ); assert(xFilter); Reference < XImporter > xImporter( xFilter, UNO_QUERY ); assert(xImporter); xImporter->setTargetDocument ( mxDoc ); if (xStatusIndicator.is()){ xStatusIndicator->setValue(nSteps++); } // Creating a ConverterBridge instance Reference< XInterface > xConvBridge( mxContext->getServiceManager()->createInstanceWithContext(udConvertClass, mxContext), UNO_QUERY); if (!xConvBridge.is()) { SAL_WARN("filter.xmlfa", "XmlFilterAdaptor: unable to create service " << udConvertClass); return false; } if (xStatusIndicator.is()) xStatusIndicator->setValue(nSteps++); Reference< XImportFilter > xConverter1( xConvBridge, UNO_QUERY ); Reference< XImportFilter2 > xConverter2( xConvBridge, UNO_QUERY ); // prevent unnecessary broadcasting when loading Reference< XModel > xModel( mxDoc, UNO_QUERY ); if( xModel.is() ) xModel->lockControllers(); comphelper::ScopeGuard guard([&]() { // cleanup when leaving if( xModel.is() ) xModel->unlockControllers(); }); //Template Loading if Required if (!msTemplateName.isEmpty()){ Reference< XStyleFamiliesSupplier > xstylefamiliessupplier(mxDoc, UNO_QUERY); Reference< XStyleLoader > xstyleLoader (xstylefamiliessupplier->getStyleFamilies(), UNO_QUERY); if(xstyleLoader.is()){ Sequence aValue = xstyleLoader->getStyleLoaderOptions(); //Load the Styles from the Template URL Supplied in the TypeDetection file if(!comphelper::isFileUrl(msTemplateName)) { SvtPathOptions aOptions; msTemplateName = aOptions.SubstituteVariable("$(progurl)") + "/" + msTemplateName; } xstyleLoader->loadStylesFromURL(msTemplateName,aValue); } } if (xStatusIndicator.is()){ xStatusIndicator->setValue(nSteps++); } // Calling Filtering Component try { Reference < XFastParser > xFastParser( xFilter, UNO_QUERY ); // SvXMLImport subclasses Reference < XDocumentHandler > xDocHandler( xFilter, UNO_QUERY ); // XMLTransformer subclasses assert(xFastParser || xDocHandler); if (xConverter2 && xFastParser) { if (!xConverter2->importer(aDescriptor,xFastParser,msUserData)) { if (xStatusIndicator.is()) xStatusIndicator->end(); return false; } } else if (xConverter1 && xDocHandler) { if (!xConverter1->importer(aDescriptor,xDocHandler,msUserData)) { if (xStatusIndicator.is()) xStatusIndicator->end(); return false; } } else if (xConverter1 && xFastParser) { auto pImport = static_cast(xFastParser.get()); Reference xLegacyDocHandler = new SvXMLLegacyToFastDocHandler(pImport); if (!xConverter1->importer(aDescriptor,xLegacyDocHandler,msUserData)) { if (xStatusIndicator.is()) xStatusIndicator->end(); return false; } } else { SAL_WARN("filter.xmlfa", "no working combination found"); assert(false); if (xStatusIndicator.is()) xStatusIndicator->end(); return false; } } catch( const Exception& ) { TOOLS_WARN_EXCEPTION("filter.xmlfa", "XmlFilterAdaptor"); if (xStatusIndicator.is()) xStatusIndicator->end(); return false; } if (xStatusIndicator.is()) { xStatusIndicator->setValue(nSteps++); xStatusIndicator->end(); } return true; } bool XmlFilterAdaptor::exportImpl( const Sequence< css::beans::PropertyValue >& aDescriptor ) { OUString udConvertClass = msUserData[0]; OUString udExport = msUserData[3]; // Status Bar sal_Int32 nSteps= 1; utl::MediaDescriptor aMediaMap(aDescriptor); Reference< XStatusIndicator > xStatusIndicator(aMediaMap.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_STATUSINDICATOR, Reference< XStatusIndicator >())); if (xStatusIndicator.is()) xStatusIndicator->start( "Saving :", 3); // Set up converter bridge. Reference< css::xml::XExportFilter > xConverter(mxContext->getServiceManager()->createInstanceWithContext( udConvertClass, mxContext ), UNO_QUERY); if (!xConverter.is()) { SAL_WARN("filter.xmlfa", "XmlFilterAdaptor: unable to create service " << udConvertClass); return false; } if (xStatusIndicator.is()) xStatusIndicator->setValue(nSteps++); //put filter component into exporting state if (!xConverter->exporter(aDescriptor, msUserData)) { if (xStatusIndicator.is()) xStatusIndicator->end(); return false; } if (xStatusIndicator.is()) xStatusIndicator->setValue(nSteps++); try{ // create the xml exporter service and supply the converter component // which implements the document handler // pretty printing is confusing for some filters so it is disabled by default bool bPrettyPrint = (msUserData.getLength() > 6 && msUserData[6].equalsIgnoreAsciiCase("true")); // export of element for elements are // needed for certain filters. bool bExportTextNumberElementForListItems = ( msUserData.getLength() > 7 && msUserData[7].equalsIgnoreAsciiCase("true") ); // get the base URI, so we can use relative links OUString aBaseURI; if (aMediaMap.find(OUString( "URL" ))->second >>= aBaseURI) { INetURLObject aURLObj(aBaseURI); // base URI in this case is the URI of the actual saving location // aURLObj.removeSegment(); aBaseURI = aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE); } // create an XProperty set to configure the exporter for pretty printing static const PropertyMapEntry aImportInfoMap[] = { { OUString("UsePrettyPrinting"), 0, cppu::UnoType::get(), PropertyAttribute::MAYBEVOID, 0}, { OUString("ExportTextNumberElement"), 0, cppu::UnoType::get(), PropertyAttribute::MAYBEVOID, 0}, { OUString("BaseURI"), 0, ::cppu::UnoType::get(), PropertyAttribute::MAYBEVOID, 0}, }; Reference< XPropertySet > xInfoSet( GenericPropertySet_CreateInstance( new PropertySetInfo( aImportInfoMap ) ) ); xInfoSet->setPropertyValue("UsePrettyPrinting", Any( bPrettyPrint )); xInfoSet->setPropertyValue( "ExportTextNumberElement", Any( bExportTextNumberElementForListItems )); xInfoSet->setPropertyValue("BaseURI", Any( aBaseURI )); Sequence < Any > aAnys{ Any(xConverter), Any(xInfoSet) }; Reference< XExporter > xExporter( mxContext->getServiceManager()->createInstanceWithArgumentsAndContext( udExport, aAnys, mxContext ), UNO_QUERY_THROW ); // attach to source document xExporter->setSourceDocument( mxDoc ); // get XFilter interface Reference< XFilter > xFilter( xExporter, UNO_QUERY_THROW ); if (xStatusIndicator.is()) xStatusIndicator->setValue(nSteps++); // call the actual filtering component if (!xFilter->filter(aDescriptor)) { if (xStatusIndicator.is()) xStatusIndicator->end(); return false; } } catch (const Exception&) { TOOLS_WARN_EXCEPTION("filter.xmlfa", "XmlFilterAdaptor"); if (xStatusIndicator.is()) xStatusIndicator->end(); return false; } // done if (xStatusIndicator.is()) xStatusIndicator->end(); return true; } sal_Bool SAL_CALL XmlFilterAdaptor::filter( const Sequence< css::beans::PropertyValue >& aDescriptor ) { return meType == FILTER_EXPORT ? exportImpl ( aDescriptor ) : importImpl ( aDescriptor ); } void SAL_CALL XmlFilterAdaptor::cancel( ) { } // XExporter void SAL_CALL XmlFilterAdaptor::setSourceDocument( const Reference< css::lang::XComponent >& xDoc ) { meType = FILTER_EXPORT; mxDoc = xDoc; } // XImporter void SAL_CALL XmlFilterAdaptor::setTargetDocument( const Reference< css::lang::XComponent >& xDoc ) { meType = FILTER_IMPORT; mxDoc = xDoc; } // XInitialization void SAL_CALL XmlFilterAdaptor::initialize( const Sequence< Any >& aArguments ) { Sequence < PropertyValue > aAnySeq; if ( aArguments.hasElements() && ( aArguments[0] >>= aAnySeq ) ) { comphelper::SequenceAsHashMap aMap(aAnySeq); msFilterName = aMap.getUnpackedValueOrDefault( "Type", OUString()); msUserData = aMap.getUnpackedValueOrDefault( "UserData", Sequence< OUString >()); msTemplateName = aMap.getUnpackedValueOrDefault( "TemplateName", OUString()); } } // XServiceInfo OUString SAL_CALL XmlFilterAdaptor::getImplementationName( ) { return "com.sun.star.comp.Writer.XmlFilterAdaptor"; } sal_Bool SAL_CALL XmlFilterAdaptor::supportsService( const OUString& rServiceName ) { return cppu::supportsService( this, rServiceName ); } Sequence< OUString > SAL_CALL XmlFilterAdaptor::getSupportedServiceNames( ) { return { "com.sun.star.document.ExportFilter", "com.sun.star.document.ImportFilter" }; } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* filter_XmlFilterAdaptor_get_implementation( css::uno::XComponentContext* context, css::uno::Sequence const&) { return cppu::acquire(new XmlFilterAdaptor(context)); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */