diff options
Diffstat (limited to 'xmloff/source/core/xmlexp.cxx')
-rw-r--r-- | xmloff/source/core/xmlexp.cxx | 2475 |
1 files changed, 2475 insertions, 0 deletions
diff --git a/xmloff/source/core/xmlexp.cxx b/xmloff/source/core/xmlexp.cxx new file mode 100644 index 000000000..55e9b1956 --- /dev/null +++ b/xmloff/source/core/xmlexp.cxx @@ -0,0 +1,2475 @@ +/* -*- 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 <config_wasm_strip.h> + +#include <memory> +#include <sal/config.h> +#include <sal/log.hxx> + +#include <mutex> +#include <stack> +#include <optional> +#include <utility> + +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> +#include <tools/urlobj.hxx> +#include <vcl/graph.hxx> +#include <comphelper/genericpropertyset.hxx> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/document/XBinaryStreamResolver.hpp> +#include <com/sun/star/document/XEmbeddedObjectResolver.hpp> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/xml/sax/SAXInvalidCharacterException.hpp> +#include <com/sun/star/uri/XUriReferenceFactory.hpp> +#include <com/sun/star/uri/UriReferenceFactory.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/MeasureUnit.hpp> +#include <i18nlangtag/languagetag.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertysetinfo.hxx> +#include <comphelper/propertyvalue.hxx> +#include <xmloff/attrlist.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlnumfe.hxx> +#include <xmloff/xmlmetae.hxx> +#include <xmloff/XMLSettingsExportContext.hxx> +#include <xmloff/XMLEventExport.hxx> +#include <xmloff/ProgressBarHelper.hxx> +#include <XMLStarBasicExportHandler.hxx> +#include <XMLScriptExportHandler.hxx> +#include <xmloff/SettingsExportHelper.hxx> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/document/XViewDataSupplier.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XModule.hpp> +#include <xmloff/GradientStyle.hxx> +#include <xmloff/HatchStyle.hxx> +#include <xmloff/ImageStyle.hxx> +#include <TransGradientStyle.hxx> +#include <xmloff/MarkerStyle.hxx> +#include <xmloff/DashStyle.hxx> +#include <xmloff/XMLFontAutoStylePool.hxx> +#include <XMLImageMapExport.hxx> +#include <XMLBase64Export.hxx> +#include <xmloff/xmlerror.hxx> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/lang/ServiceNotRegisteredException.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <xmloff/XMLFilterServiceNames.h> +#include <XMLEmbeddedObjectExportFilter.hxx> +#include <XMLBasicExportFilter.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/extract.hxx> +#include <comphelper/SetFlagContextHelper.hxx> +#include <PropertySetMerger.hxx> + +#include <unotools/docinfohelper.hxx> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XMLOasisBasicExporter.hpp> +#include <com/sun/star/embed/XEncryptionProtectedSource2.hpp> +#include <com/sun/star/document/XGraphicStorageHandler.hpp> +#include <com/sun/star/rdf/XMetadatable.hpp> +#include <RDFaExportHelper.hxx> + +#include <comphelper/xmltools.hxx> +#include <comphelper/graphicmimetype.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::io; +using namespace ::xmloff::token; + +constexpr OUStringLiteral XML_MODEL_SERVICE_WRITER = u"com.sun.star.text.TextDocument"; +constexpr OUStringLiteral XML_MODEL_SERVICE_CALC = u"com.sun.star.sheet.SpreadsheetDocument"; +constexpr OUStringLiteral XML_MODEL_SERVICE_DRAW = u"com.sun.star.drawing.DrawingDocument"; +constexpr OUStringLiteral XML_MODEL_SERVICE_IMPRESS = u"com.sun.star.presentation.PresentationDocument"; +constexpr OUStringLiteral XML_MODEL_SERVICE_MATH = u"com.sun.star.formula.FormulaProperties"; +constexpr OUStringLiteral XML_MODEL_SERVICE_CHART = u"com.sun.star.chart.ChartDocument"; + +constexpr OUStringLiteral XML_USEPRETTYPRINTING = u"UsePrettyPrinting"; + +constexpr OUStringLiteral XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE = u"vnd.sun.star.GraphicObject:"; +constexpr OUStringLiteral XML_EMBEDDEDOBJECT_URL_BASE = u"vnd.sun.star.EmbeddedObject:"; + +const std::pair<OUString, OUString> aServiceMap[] = { + { XML_MODEL_SERVICE_WRITER, XML_EXPORT_FILTER_WRITER }, + { XML_MODEL_SERVICE_CALC, XML_EXPORT_FILTER_CALC }, + { XML_MODEL_SERVICE_IMPRESS, XML_EXPORT_FILTER_IMPRESS }, // Impress supports DrawingDocument, + { XML_MODEL_SERVICE_DRAW, XML_EXPORT_FILTER_DRAW }, // too, so it must appear before Draw + { XML_MODEL_SERVICE_MATH, XML_EXPORT_FILTER_MATH }, + { XML_MODEL_SERVICE_CHART, XML_EXPORT_FILTER_CHART }, +}; + +namespace { + +class SettingsExportFacade : public ::xmloff::XMLSettingsExportContext +{ +public: + explicit SettingsExportFacade( SvXMLExport& i_rExport ) + :m_rExport( i_rExport ) + { + } + + virtual ~SettingsExportFacade() + { + } + + virtual void AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, + const OUString& i_rValue ) override; + virtual void AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, + enum ::xmloff::token::XMLTokenEnum i_eValue ) override; + + virtual void StartElement( enum ::xmloff::token::XMLTokenEnum i_eName ) override; + virtual void EndElement( const bool i_bIgnoreWhitespace ) override; + + virtual void Characters( const OUString& i_rCharacters ) override; + + virtual css::uno::Reference< css::uno::XComponentContext > + GetComponentContext() const override; +private: + SvXMLExport& m_rExport; + ::std::stack< OUString > m_aElements; +}; + +} + +void SettingsExportFacade::AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, const OUString& i_rValue ) +{ + m_rExport.AddAttribute( XML_NAMESPACE_CONFIG, i_eName, i_rValue ); +} + +void SettingsExportFacade::AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, enum ::xmloff::token::XMLTokenEnum i_eValue ) +{ + m_rExport.AddAttribute( XML_NAMESPACE_CONFIG, i_eName, i_eValue ); +} + +void SettingsExportFacade::StartElement( enum ::xmloff::token::XMLTokenEnum i_eName ) +{ + const OUString sElementName( m_rExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_CONFIG, GetXMLToken( i_eName ) ) ); + m_rExport.StartElement( sElementName, true/*i_bIgnoreWhitespace*/ ); + m_aElements.push( sElementName ); +} + +void SettingsExportFacade::EndElement( const bool i_bIgnoreWhitespace ) +{ + const OUString sElementName( m_aElements.top() ); + m_rExport.EndElement( sElementName, i_bIgnoreWhitespace ); + m_aElements.pop(); +} + +void SettingsExportFacade::Characters( const OUString& i_rCharacters ) +{ + m_rExport.GetDocHandler()->characters( i_rCharacters ); +} + +Reference< XComponentContext > SettingsExportFacade::GetComponentContext() const +{ + return m_rExport.getComponentContext(); +} + +namespace { + +class SvXMLExportEventListener : public cppu::WeakImplHelper< + css::lang::XEventListener > +{ +private: + SvXMLExport* pExport; + +public: + explicit SvXMLExportEventListener(SvXMLExport* pExport); + + // XEventListener + virtual void SAL_CALL disposing(const lang::EventObject& rEventObject) override; +}; + +} + +SvXMLExportEventListener::SvXMLExportEventListener(SvXMLExport* pTempExport) + : pExport(pTempExport) +{ +} + +// XEventListener +void SAL_CALL SvXMLExportEventListener::disposing( const lang::EventObject& ) +{ + if (pExport) + { + pExport->DisposingModel(); + pExport = nullptr; + } +} + +class SvXMLExport_Impl +{ +public: + SvXMLExport_Impl(); + + ::comphelper::UnoInterfaceToUniqueIdentifierMapper maInterfaceToIdentifierMapper; + uno::Reference< uri::XUriReferenceFactory > mxUriReferenceFactory; + OUString msPackageURI; + OUString msPackageURIScheme; + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + bool mbOutlineStyleAsNormalListStyle; + + uno::Reference< embed::XStorage > mxTargetStorage; + + std::optional<SvtSaveOptions::ODFSaneDefaultVersion> m_oOverrideODFVersion; + + /// name of stream in package, e.g., "content.xml" + OUString mStreamName; + + OUString maSrcShellID; + OUString maDestShellID; + + /// stack of backed up namespace maps + /// long: depth at which namespace map has been backed up into the stack + ::std::stack< ::std::pair< std::unique_ptr<SvXMLNamespaceMap>, tools::Long > > mNamespaceMaps; + /// counts depth (number of open elements/start tags) + tools::Long mDepth; + + ::std::unique_ptr< ::xmloff::RDFaExportHelper> mpRDFaHelper; + + bool mbExportTextNumberElement; + bool mbNullDateInitialized; + + void SetSchemeOf( std::u16string_view rOrigFileName ) + { + size_t nSep = rOrigFileName.find(':'); + if( nSep != std::u16string_view::npos ) + msPackageURIScheme = rOrigFileName.substr( 0, nSep ); + } +}; + +SvXMLExport_Impl::SvXMLExport_Impl() +: mxUriReferenceFactory( uri::UriReferenceFactory::create(comphelper::getProcessComponentContext()) ), + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + mbOutlineStyleAsNormalListStyle( false ), + mDepth( 0 ), + mbExportTextNumberElement( false ), + mbNullDateInitialized( false ) +{ +} + +void SvXMLExport::SetDocHandler( const uno::Reference< xml::sax::XDocumentHandler > &rHandler ) +{ + mxHandler = rHandler; + mxExtHandler.set( mxHandler, UNO_QUERY ); +} + +void SvXMLExport::InitCtor_() +{ + // note: it is not necessary to add XML_NP_XML (it is declared implicitly) + if( getExportFlags() & ~SvXMLExportFlags::OASIS ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_OFFICE), GetXMLToken(XML_N_OFFICE), XML_NAMESPACE_OFFICE ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_OOO), GetXMLToken(XML_N_OOO), XML_NAMESPACE_OOO ); + } + if( getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::FONTDECLS) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_FO), GetXMLToken(XML_N_FO_COMPAT), XML_NAMESPACE_FO ); + } + if( getExportFlags() & (SvXMLExportFlags::META|SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SCRIPTS|SvXMLExportFlags::SETTINGS) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_XLINK), GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK ); + } + if( getExportFlags() & SvXMLExportFlags::SETTINGS ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_CONFIG), GetXMLToken(XML_N_CONFIG), XML_NAMESPACE_CONFIG ); + } + + if( getExportFlags() & (SvXMLExportFlags::META|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_DC), GetXMLToken(XML_N_DC), XML_NAMESPACE_DC ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_META), GetXMLToken(XML_N_META), XML_NAMESPACE_META ); + } + if( getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::FONTDECLS) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_STYLE), GetXMLToken(XML_N_STYLE), XML_NAMESPACE_STYLE ); + } + + // namespaces for documents + if( getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_DC), GetXMLToken(XML_N_DC), XML_NAMESPACE_DC ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_TEXT), GetXMLToken(XML_N_TEXT), XML_NAMESPACE_TEXT ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_DRAW), GetXMLToken(XML_N_DRAW), XML_NAMESPACE_DRAW ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_DR3D), GetXMLToken(XML_N_DR3D), XML_NAMESPACE_DR3D ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_SVG), GetXMLToken(XML_N_SVG_COMPAT), XML_NAMESPACE_SVG ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_CHART), GetXMLToken(XML_N_CHART), XML_NAMESPACE_CHART ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_RPT), GetXMLToken(XML_N_RPT), XML_NAMESPACE_REPORT ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_TABLE), GetXMLToken(XML_N_TABLE), XML_NAMESPACE_TABLE ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_NUMBER),GetXMLToken(XML_N_NUMBER), XML_NAMESPACE_NUMBER ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_OOOW), GetXMLToken(XML_N_OOOW), XML_NAMESPACE_OOOW ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_OOOC), GetXMLToken(XML_N_OOOC), XML_NAMESPACE_OOOC ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_OF), GetXMLToken(XML_N_OF), XML_NAMESPACE_OF ); + + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + mpNamespaceMap->Add( + GetXMLToken(XML_NP_TABLE_EXT), GetXMLToken(XML_N_TABLE_EXT), XML_NAMESPACE_TABLE_EXT); + mpNamespaceMap->Add( + GetXMLToken(XML_NP_CALC_EXT), GetXMLToken(XML_N_CALC_EXT), XML_NAMESPACE_CALC_EXT); + mpNamespaceMap->Add( + GetXMLToken(XML_NP_DRAW_EXT), GetXMLToken(XML_N_DRAW_EXT), XML_NAMESPACE_DRAW_EXT); + mpNamespaceMap->Add( + GetXMLToken(XML_NP_LO_EXT), GetXMLToken(XML_N_LO_EXT), + XML_NAMESPACE_LO_EXT); + mpNamespaceMap->Add( GetXMLToken(XML_NP_FIELD), GetXMLToken(XML_N_FIELD), XML_NAMESPACE_FIELD ); + } + } + if( getExportFlags() & (SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_MATH), GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_FORM), GetXMLToken(XML_N_FORM), XML_NAMESPACE_FORM ); + } + if( getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SCRIPTS) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_SCRIPT), GetXMLToken(XML_N_SCRIPT), XML_NAMESPACE_SCRIPT ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_DOM), GetXMLToken(XML_N_DOM), XML_NAMESPACE_DOM ); + } + if( getExportFlags() & SvXMLExportFlags::CONTENT ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_XFORMS_1_0), GetXMLToken(XML_N_XFORMS_1_0), XML_NAMESPACE_XFORMS ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_XSD), GetXMLToken(XML_N_XSD), XML_NAMESPACE_XSD ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_XSI), GetXMLToken(XML_N_XSI), XML_NAMESPACE_XSI ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_FORMX), GetXMLToken(XML_N_FORMX), XML_NAMESPACE_FORMX ); + } + + // RDFa: needed for content and header/footer styles + if( getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_XHTML), + GetXMLToken(XML_N_XHTML), XML_NAMESPACE_XHTML ); + } + // GRDDL: to convert RDFa and meta.xml to RDF + if( getExportFlags() & (SvXMLExportFlags::META|SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_GRDDL), + GetXMLToken(XML_N_GRDDL), XML_NAMESPACE_GRDDL ); + } + // CSS Text Level 3 for distributed text justification. + if ( getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES) ) + { + mpNamespaceMap->Add( + GetXMLToken(XML_NP_CSS3TEXT), GetXMLToken(XML_N_CSS3TEXT), XML_NAMESPACE_CSS3TEXT ); + } + + if (mxModel.is() && !mxEventListener.is()) + { + mxEventListener.set( new SvXMLExportEventListener(this)); + mxModel->addEventListener(mxEventListener); + } + + // Determine model type (#i51726#) + DetermineModelType_(); +} + +// Shapes in Writer cannot be named via context menu (#i51726#) +void SvXMLExport::DetermineModelType_() +{ + meModelType = SvtModuleOptions::EFactory::UNKNOWN_FACTORY; + + if ( !mxModel.is() ) + return; + + meModelType = SvtModuleOptions::ClassifyFactoryByModel( mxModel ); + + // note: MATH documents will throw NotInitializedException; maybe unit test problem + if (meModelType == SvtModuleOptions::EFactory::WRITER) + { + uno::Reference<frame::XModule> const xModule(mxModel, uno::UNO_QUERY); + bool const isBaseForm(xModule.is() && + xModule->getIdentifier() == "com.sun.star.sdb.FormDesign"); + if (isBaseForm) + { + switch (GetODFSaneDefaultVersion()) + { + case SvtSaveOptions::ODFSVER_013_EXTENDED: + SAL_INFO("xmloff.core", "tdf#138209 force form export to ODF 1.2"); + mpImpl->m_oOverrideODFVersion = SvtSaveOptions::ODFSVER_012_EXTENDED; + maUnitConv.overrideSaneDefaultVersion(SvtSaveOptions::ODFSVER_012_EXTENDED); + break; + case SvtSaveOptions::ODFSVER_013: + SAL_INFO("xmloff.core", "tdf#138209 force form export to ODF 1.2"); + mpImpl->m_oOverrideODFVersion = SvtSaveOptions::ODFSVER_012; + maUnitConv.overrideSaneDefaultVersion(SvtSaveOptions::ODFSVER_012); + break; + default: + break; + } + } + } +} + +SvXMLExport::SvXMLExport( + const uno::Reference< uno::XComponentContext >& xContext, + OUString const & implementationName, + sal_Int16 const eDefaultMeasureUnit /*css::util::MeasureUnit*/, + const enum XMLTokenEnum eClass, SvXMLExportFlags nExportFlags ) +: mpImpl( new SvXMLExport_Impl ), + m_xContext(xContext), m_implementationName(implementationName), + mxAttrList( new SvXMLAttributeList ), + mpNamespaceMap( new SvXMLNamespaceMap ), + mpAuthorIDs( new SvtSecurityMapPersonalInfo ), + maUnitConv(xContext, util::MeasureUnit::MM_100TH, eDefaultMeasureUnit, getSaneDefaultVersion()), + meClass( eClass ), + mnExportFlags( nExportFlags ), + mnErrorFlags( SvXMLErrorFlags::NO ), + msWS( GetXMLToken(XML_WS) ), + mbSaveLinkedSections(true), + mbAutoStylesCollected(false) +{ + SAL_WARN_IF( !xContext.is(), "xmloff.core", "got no service manager" ); + InitCtor_(); +} + +SvXMLExport::SvXMLExport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + const OUString &rFileName, + sal_Int16 const eDefaultMeasureUnit /*css::util::MeasureUnit*/, + const uno::Reference< xml::sax::XDocumentHandler > & rHandler) +: mpImpl( new SvXMLExport_Impl ), + m_xContext(xContext), m_implementationName(implementationName), + mxHandler( rHandler ), + mxExtHandler( rHandler, uno::UNO_QUERY ), + mxAttrList( new SvXMLAttributeList ), + msOrigFileName( rFileName ), + mpNamespaceMap( new SvXMLNamespaceMap ), + mpAuthorIDs( new SvtSecurityMapPersonalInfo ), + maUnitConv(xContext, util::MeasureUnit::MM_100TH, eDefaultMeasureUnit, getSaneDefaultVersion()), + meClass( XML_TOKEN_INVALID ), + mnExportFlags( SvXMLExportFlags::NONE ), + mnErrorFlags( SvXMLErrorFlags::NO ), + msWS( GetXMLToken(XML_WS) ), + mbSaveLinkedSections(true), + mbAutoStylesCollected(false) +{ + SAL_WARN_IF( !xContext.is(), "xmloff.core", "got no service manager" ); + mpImpl->SetSchemeOf( msOrigFileName ); + InitCtor_(); + + if (mxNumberFormatsSupplier.is()) + mpNumExport.reset( new SvXMLNumFmtExport(*this, mxNumberFormatsSupplier) ); +} + +SvXMLExport::SvXMLExport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + const OUString &rFileName, + const uno::Reference< xml::sax::XDocumentHandler > & rHandler, + const Reference< XModel >& rModel, + FieldUnit const eDefaultFieldUnit, + SvXMLExportFlags nExportFlag) +: mpImpl( new SvXMLExport_Impl ), + m_xContext(xContext), m_implementationName(implementationName), + mxModel( rModel ), + mxHandler( rHandler ), + mxExtHandler( rHandler, uno::UNO_QUERY ), + mxNumberFormatsSupplier (rModel, uno::UNO_QUERY), + mxAttrList( new SvXMLAttributeList ), + msOrigFileName( rFileName ), + mpNamespaceMap( new SvXMLNamespaceMap ), + mpAuthorIDs( new SvtSecurityMapPersonalInfo ), + maUnitConv( xContext, + util::MeasureUnit::MM_100TH, + SvXMLUnitConverter::GetMeasureUnit(eDefaultFieldUnit), + getSaneDefaultVersion()), + meClass( XML_TOKEN_INVALID ), + mnExportFlags( nExportFlag ), + mnErrorFlags( SvXMLErrorFlags::NO ), + msWS( GetXMLToken(XML_WS) ), + mbSaveLinkedSections(true), + mbAutoStylesCollected(false) +{ + SAL_WARN_IF(!xContext.is(), "xmloff.core", "got no service manager" ); + mpImpl->SetSchemeOf( msOrigFileName ); + InitCtor_(); + + if (mxNumberFormatsSupplier.is()) + mpNumExport.reset( new SvXMLNumFmtExport(*this, mxNumberFormatsSupplier) ); +} + +SvXMLExport::~SvXMLExport() +{ + mpXMLErrors.reset(); + mpImageMapExport.reset(); + mpEventExport.reset(); + mpNamespaceMap.reset(); + if (mpProgressBarHelper || mpNumExport) + { + if (mxExportInfo.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxExportInfo->getPropertySetInfo(); + if (xPropertySetInfo.is()) + { + if (mpProgressBarHelper) + { + static constexpr OUStringLiteral sProgressMax(XML_PROGRESSMAX); + static constexpr OUStringLiteral sProgressCurrent(XML_PROGRESSCURRENT); + static constexpr OUStringLiteral sRepeat(XML_PROGRESSREPEAT); + if (xPropertySetInfo->hasPropertyByName(sProgressMax) && + xPropertySetInfo->hasPropertyByName(sProgressCurrent)) + { + sal_Int32 nProgressMax(mpProgressBarHelper->GetReference()); + sal_Int32 nProgressCurrent(mpProgressBarHelper->GetValue()); + mxExportInfo->setPropertyValue(sProgressMax, uno::Any(nProgressMax)); + mxExportInfo->setPropertyValue(sProgressCurrent, uno::Any(nProgressCurrent)); + } + if (xPropertySetInfo->hasPropertyByName(sRepeat)) + mxExportInfo->setPropertyValue(sRepeat, css::uno::Any(mpProgressBarHelper->GetRepeat())); + } + if (mpNumExport && (mnExportFlags & (SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::STYLES))) + { + static constexpr OUStringLiteral sWrittenNumberFormats(XML_WRITTENNUMBERSTYLES); + if (xPropertySetInfo->hasPropertyByName(sWrittenNumberFormats)) + { + mxExportInfo->setPropertyValue(sWrittenNumberFormats, Any(mpNumExport->GetWasUsed())); + } + } + } + } + mpProgressBarHelper.reset(); + mpNumExport.reset(); + } + + if (mxEventListener.is() && mxModel.is()) + mxModel->removeEventListener(mxEventListener); +} + +// XExporter +void SAL_CALL SvXMLExport::setSourceDocument( const uno::Reference< lang::XComponent >& xDoc ) +{ + mxModel.set( xDoc, UNO_QUERY ); + if( !mxModel.is() ) + throw lang::IllegalArgumentException(); + if (mxModel.is() && ! mxEventListener.is()) + { + mxEventListener.set( new SvXMLExportEventListener(this)); + mxModel->addEventListener(mxEventListener); + } + + if(!mxNumberFormatsSupplier.is() ) + { + mxNumberFormatsSupplier.set(mxModel, css::uno::UNO_QUERY); + if(mxNumberFormatsSupplier.is() && mxHandler.is()) + mpNumExport.reset( new SvXMLNumFmtExport(*this, mxNumberFormatsSupplier) ); + } + if (mxExportInfo.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxExportInfo->getPropertySetInfo(); + if (xPropertySetInfo.is()) + { + OUString sUsePrettyPrinting(XML_USEPRETTYPRINTING); + if (xPropertySetInfo->hasPropertyByName(sUsePrettyPrinting)) + { + uno::Any aAny = mxExportInfo->getPropertyValue(sUsePrettyPrinting); + if (::cppu::any2bool(aAny)) + mnExportFlags |= SvXMLExportFlags::PRETTY; + else + mnExportFlags &= ~SvXMLExportFlags::PRETTY; + } + + if (mpNumExport && (mnExportFlags & (SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::STYLES))) + { + OUString sWrittenNumberFormats(XML_WRITTENNUMBERSTYLES); + if (xPropertySetInfo->hasPropertyByName(sWrittenNumberFormats)) + { + uno::Any aAny = mxExportInfo->getPropertyValue(sWrittenNumberFormats); + uno::Sequence<sal_Int32> aWasUsed; + if(aAny >>= aWasUsed) + mpNumExport->SetWasUsed(aWasUsed); + } + } + } + } + + // namespaces for user defined attributes + Reference< XMultiServiceFactory > xFactory( mxModel, UNO_QUERY ); + if( xFactory.is() ) + { + try + { + Reference < XInterface > xIfc = + xFactory->createInstance("com.sun.star.xml.NamespaceMap"); + if( xIfc.is() ) + { + Reference< XNameAccess > xNamespaceMap( xIfc, UNO_QUERY ); + if( xNamespaceMap.is() ) + { + const Sequence< OUString > aPrefixes( xNamespaceMap->getElementNames() ); + for( OUString const & prefix : aPrefixes ) + { + OUString aURL; + if( xNamespaceMap->getByName( prefix ) >>= aURL ) + GetNamespaceMap_().Add( prefix, aURL ); + } + } + } + } + catch(const css::uno::Exception&) + { + } + } + + // Determine model type (#i51726#) + DetermineModelType_(); +} + +// XInitialize +void SAL_CALL SvXMLExport::initialize( const uno::Sequence< uno::Any >& aArguments ) +{ + // #93186# we need to queryInterface every single Any with any expected outcome. This variable hold the queryInterface results. + + for( const auto& rAny : aArguments ) + { + Reference<XInterface> xValue; + rAny >>= xValue; + + // status indicator + uno::Reference<task::XStatusIndicator> xTmpStatus( xValue, UNO_QUERY ); + if ( xTmpStatus.is() ) + mxStatusIndicator = xTmpStatus; + + // graphic storage handler + uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler(xValue, UNO_QUERY); + if (xGraphicStorageHandler.is()) + mxGraphicStorageHandler = xGraphicStorageHandler; + + // object resolver + uno::Reference<document::XEmbeddedObjectResolver> xTmpObjectResolver( + xValue, UNO_QUERY ); + if ( xTmpObjectResolver.is() ) + mxEmbeddedResolver = xTmpObjectResolver; + + // document handler + uno::Reference<xml::sax::XDocumentHandler> xTmpDocHandler( + xValue, UNO_QUERY ); + if( xTmpDocHandler.is() ) + { + mxHandler = xTmpDocHandler; + rAny >>= mxExtHandler; + + if (mxNumberFormatsSupplier.is() && mpNumExport == nullptr) + mpNumExport.reset( new SvXMLNumFmtExport(*this, mxNumberFormatsSupplier) ); + } + + // property set to transport data across + uno::Reference<beans::XPropertySet> xTmpPropertySet( + xValue, UNO_QUERY ); + if( xTmpPropertySet.is() ) + mxExportInfo = xTmpPropertySet; + } + + if( !mxExportInfo.is() ) + return; + + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = + mxExportInfo->getPropertySetInfo(); + static constexpr OUStringLiteral sBaseURI = u"BaseURI"; + if( xPropertySetInfo->hasPropertyByName(sBaseURI) ) + { + uno::Any aAny = mxExportInfo->getPropertyValue(sBaseURI); + aAny >>= msOrigFileName; + mpImpl->msPackageURI = msOrigFileName; + mpImpl->SetSchemeOf( msOrigFileName ); + } + OUString sRelPath; + static constexpr OUStringLiteral sStreamRelPath = u"StreamRelPath"; + if( xPropertySetInfo->hasPropertyByName(sStreamRelPath) ) + { + uno::Any aAny = mxExportInfo->getPropertyValue(sStreamRelPath); + aAny >>= sRelPath; + } + OUString sName; + static constexpr OUStringLiteral sStreamName = u"StreamName"; + if( xPropertySetInfo->hasPropertyByName(sStreamName) ) + { + uno::Any aAny = mxExportInfo->getPropertyValue(sStreamName); + aAny >>= sName; + } + if( !msOrigFileName.isEmpty() && !sName.isEmpty() ) + { + INetURLObject aBaseURL( msOrigFileName ); + if( !sRelPath.isEmpty() ) + aBaseURL.insertName( sRelPath ); + aBaseURL.insertName( sName ); + msOrigFileName = aBaseURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri); + } + mpImpl->mStreamName = sName; // Note: may be empty (XSLT) + + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + static const OUStringLiteral sOutlineStyleAsNormalListStyle( + u"OutlineStyleAsNormalListStyle" ); + if( xPropertySetInfo->hasPropertyByName( sOutlineStyleAsNormalListStyle ) ) + { + uno::Any aAny = mxExportInfo->getPropertyValue( sOutlineStyleAsNormalListStyle ); + aAny >>= mpImpl->mbOutlineStyleAsNormalListStyle; + } + + OUString sTargetStorage( "TargetStorage" ); + if( xPropertySetInfo->hasPropertyByName( sTargetStorage ) ) + mxExportInfo->getPropertyValue( sTargetStorage ) >>= mpImpl->mxTargetStorage; + + static const OUStringLiteral sExportTextNumberElement( + u"ExportTextNumberElement" ); + if( xPropertySetInfo->hasPropertyByName( sExportTextNumberElement ) ) + { + uno::Any aAny = mxExportInfo->getPropertyValue( sExportTextNumberElement ); + aAny >>= mpImpl->mbExportTextNumberElement; + } +} + +// XFilter +sal_Bool SAL_CALL SvXMLExport::filter( const uno::Sequence< beans::PropertyValue >& aDescriptor ) +{ + // check for xHandler first... should have been supplied in initialize + if( !mxHandler.is() ) + return false; + + try + { + const SvXMLExportFlags nTest = + SvXMLExportFlags::META|SvXMLExportFlags::STYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SETTINGS; + if( (mnExportFlags & nTest) == nTest && msOrigFileName.isEmpty() ) + { + // evaluate descriptor only for flat files and if a base URI + // has not been provided already + + for( const auto& rProp : aDescriptor ) + { + const OUString& rPropName = rProp.Name; + const Any& rValue = rProp.Value; + + if ( rPropName == "FileName" ) + { + if( !(rValue >>= msOrigFileName ) ) + return false; + } + else if ( rPropName == "FilterName" ) + { + if( !(rValue >>= msFilterName ) ) + return false; + } + } + } + + for( const auto& rProp : aDescriptor ) + { + const OUString& rPropName = rProp.Name; + const Any& rValue = rProp.Value; + + if (rPropName == "SourceShellID") + { + if (!(rValue >>= mpImpl->maSrcShellID)) + return false; + } + else if (rPropName == "DestinationShellID") + { + if (!(rValue >>= mpImpl->maDestShellID)) + return false; + } + else if( rPropName == "ImageFilter") + { + if (!(rValue >>= msImgFilterName)) + return false; + } + } + + + exportDoc( meClass ); + } + catch(const uno::Exception& e) + { + // We must catch exceptions, because according to the + // API definition export must not throw one! + css::uno::Any ex(cppu::getCaughtException()); + OUString sMessage( ex.getValueTypeName() + ": \"" + e.Message + "\""); + if (e.Context.is()) + { + const char* pContext = typeid(*e.Context).name(); + sMessage += " (context: " + OUString::createFromAscii(pContext) + " )"; + } + SetError( XMLERROR_FLAG_ERROR | XMLERROR_FLAG_SEVERE | XMLERROR_API, + Sequence<OUString>(), sMessage, nullptr ); + } + + // return true only if no error occurred + return (mnErrorFlags & (SvXMLErrorFlags::DO_NOTHING|SvXMLErrorFlags::ERROR_OCCURRED)) == SvXMLErrorFlags::NO; +} + +void SAL_CALL SvXMLExport::cancel() +{ + // stop export + Sequence<OUString> aEmptySeq; + SetError(XMLERROR_CANCEL|XMLERROR_FLAG_SEVERE, aEmptySeq); +} + +OUString SAL_CALL SvXMLExport::getName( ) +{ + return msFilterName; +} + +void SAL_CALL SvXMLExport::setName( const OUString& ) +{ + // do nothing, because it is not possible to set the FilterName +} + +// XServiceInfo +OUString SAL_CALL SvXMLExport::getImplementationName( ) +{ + return m_implementationName; +} + +sal_Bool SAL_CALL SvXMLExport::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL SvXMLExport::getSupportedServiceNames( ) +{ + return { "com.sun.star.document.ExportFilter", "com.sun.star.xml.XMLExportFilter" }; +} + +OUString +SvXMLExport::EnsureNamespace(OUString const & i_rNamespace) +{ + OUString const aPreferredPrefix("gen"); + OUString sPrefix; + sal_uInt16 nKey( GetNamespaceMap_().GetKeyByName( i_rNamespace ) ); + if( XML_NAMESPACE_UNKNOWN == nKey ) + { + // There is no prefix for the namespace, so + // we have to generate one and have to add it. + sPrefix = aPreferredPrefix; + nKey = GetNamespaceMap_().GetKeyByPrefix( sPrefix ); + sal_Int32 n( 0 ); + OUStringBuffer buf; + while( nKey != USHRT_MAX ) + { + buf.append( aPreferredPrefix ); + buf.append( ++n ); + sPrefix = buf.makeStringAndClear(); + nKey = GetNamespaceMap_().GetKeyByPrefix( sPrefix ); + } + + if (mpImpl->mNamespaceMaps.empty() + || (mpImpl->mNamespaceMaps.top().second != mpImpl->mDepth)) + { + // top was created for lower depth... need a new namespace map! + auto pNew = new SvXMLNamespaceMap( *mpNamespaceMap ); + mpImpl->mNamespaceMaps.push( + ::std::make_pair(std::move(mpNamespaceMap), mpImpl->mDepth) ); + mpNamespaceMap.reset( pNew ); + } + + // add the namespace to the map and as attribute + mpNamespaceMap->Add( sPrefix, i_rNamespace ); + AddAttribute( GetXMLToken(XML_XMLNS) + ":" + sPrefix, i_rNamespace ); + } + else + { + // If there is a prefix for the namespace, reuse that. + sPrefix = GetNamespaceMap_().GetPrefixByKey( nKey ); + } + return sPrefix; +} + +void SvXMLExport::AddAttribute( sal_uInt16 nPrefixKey, const OUString& rName, + const OUString& rValue ) +{ + AddAttribute(GetNamespaceMap_().GetQNameByKey(nPrefixKey, rName), rValue); +} + +void SvXMLExport::AddAttribute( sal_uInt16 nPrefixKey, + enum XMLTokenEnum eName, + const OUString& rValue ) +{ + AddAttribute(nPrefixKey, GetXMLToken(eName), rValue); +} + +void SvXMLExport::AddAttribute( sal_uInt16 nPrefixKey, + enum XMLTokenEnum eName, + enum XMLTokenEnum eValue) +{ + AddAttribute(nPrefixKey, eName, GetXMLToken(eValue)); +} + +void SvXMLExport::AddAttribute( const OUString& rQName, + const OUString& rValue ) +{ + mxAttrList->AddAttribute( + rQName, + rValue ); +} + +void SvXMLExport::AddAttribute( const OUString& rQName, + enum ::xmloff::token::XMLTokenEnum eValue ) +{ + AddAttribute(rQName, GetXMLToken(eValue)); +} + +void SvXMLExport::AddLanguageTagAttributes( sal_uInt16 nPrefix, sal_uInt16 nPrefixRfc, + const css::lang::Locale& rLocale, bool bWriteEmpty ) +{ + if (rLocale.Variant.isEmpty()) + { + // Per convention The BCP 47 string is always stored in Variant, if + // that is empty we have a plain language-country combination, no need + // to convert to LanguageTag first. Also catches the case of empty + // locale denoting system locale. + xmloff::token::XMLTokenEnum eLanguage, eCountry; + eLanguage = XML_LANGUAGE; + eCountry = XML_COUNTRY; + if (bWriteEmpty || !rLocale.Language.isEmpty()) + AddAttribute( nPrefix, eLanguage, rLocale.Language); + if (bWriteEmpty || !rLocale.Country.isEmpty()) + AddAttribute( nPrefix, eCountry, rLocale.Country); + } + else + { + LanguageTag aLanguageTag( rLocale); + AddLanguageTagAttributes( nPrefix, nPrefixRfc, aLanguageTag, bWriteEmpty); + } +} + +void SvXMLExport::AddLanguageTagAttributes( sal_uInt16 nPrefix, sal_uInt16 nPrefixRfc, + const LanguageTag& rLanguageTag, bool bWriteEmpty ) +{ + if (rLanguageTag.isIsoODF()) + { + if (bWriteEmpty || !rLanguageTag.isSystemLocale()) + { + AddAttribute( nPrefix, XML_LANGUAGE, rLanguageTag.getLanguage()); + if (rLanguageTag.hasScript() && getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + AddAttribute( nPrefix, XML_SCRIPT, rLanguageTag.getScript()); + if (bWriteEmpty || !rLanguageTag.getCountry().isEmpty()) + AddAttribute( nPrefix, XML_COUNTRY, rLanguageTag.getCountry()); + } + } + else + { + if (getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + AddAttribute( nPrefixRfc, XML_RFC_LANGUAGE_TAG, rLanguageTag.getBcp47()); + // Also in case of non-pure-ISO tag store best matching fo: attributes + // for consumers not handling *:rfc-language-tag, ensuring that only + // valid ISO codes are stored. Here the bWriteEmpty parameter has no + // meaning. + OUString aLanguage, aScript, aCountry; + rLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry); + if (!aLanguage.isEmpty()) + { + AddAttribute( nPrefix, XML_LANGUAGE, aLanguage); + if (!aScript.isEmpty() && getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + AddAttribute( nPrefix, XML_SCRIPT, aScript); + if (!aCountry.isEmpty()) + AddAttribute( nPrefix, XML_COUNTRY, aCountry); + } + } +} + +void SvXMLExport::AddAttributeList( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + if( xAttrList.is()) + mxAttrList->AppendAttributeList( xAttrList ); +} + +void SvXMLExport::ClearAttrList() +{ + mxAttrList->Clear(); +} + +#ifdef DBG_UTIL +void SvXMLExport::CheckAttrList() +{ + SAL_WARN_IF( mxAttrList->getLength(), "xmloff.core", "XMLExport::CheckAttrList: list is not empty" ); +} +#endif + +void SvXMLExport::ImplExportMeta() +{ + CheckAttrList(); + + ExportMeta_(); +} + +void SvXMLExport::ImplExportSettings() +{ + CheckAttrList(); + + ::std::vector< SettingsGroup > aSettings; + sal_Int32 nSettingsCount = 0; + + // view settings + uno::Sequence< beans::PropertyValue > aViewSettings; + GetViewSettingsAndViews( aViewSettings ); + aSettings.emplace_back( XML_VIEW_SETTINGS, aViewSettings ); + nSettingsCount += aViewSettings.getLength(); + + // configuration settings + uno::Sequence<beans::PropertyValue> aConfigSettings; + GetConfigurationSettings( aConfigSettings ); + aSettings.emplace_back( XML_CONFIGURATION_SETTINGS, aConfigSettings ); + nSettingsCount += aConfigSettings.getLength(); + + // any document specific settings + nSettingsCount += GetDocumentSpecificSettings( aSettings ); + + { + SvXMLElementExport aElem( *this, + nSettingsCount != 0, + XML_NAMESPACE_OFFICE, XML_SETTINGS, + true, true ); + + SettingsExportFacade aSettingsExportContext( *this ); + XMLSettingsExportHelper aSettingsExportHelper( aSettingsExportContext ); + + for (auto const& settings : aSettings) + { + if ( !settings.aSettings.hasElements() ) + continue; + + const OUString& sSettingsName( GetXMLToken( settings.eGroupName ) ); + OUString sQName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OOO, sSettingsName ); + aSettingsExportHelper.exportAllSettings( settings.aSettings, sQName ); + } + } +} + +void SvXMLExport::ImplExportStyles() +{ + CheckAttrList(); + + { + // <style:styles> + SvXMLElementExport aElem( *this, XML_NAMESPACE_OFFICE, XML_STYLES, + true, true ); + + ExportStyles_( false ); + } + + // transfer style names (+ families) TO other components (if appropriate) + if( ( mnExportFlags & SvXMLExportFlags::CONTENT ) || !mxExportInfo.is() ) + return; + + static constexpr OUStringLiteral sStyleNames( u"StyleNames" ); + static constexpr OUStringLiteral sStyleFamilies( u"StyleFamilies" ); + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxExportInfo->getPropertySetInfo(); + if ( xPropertySetInfo->hasPropertyByName( sStyleNames ) && xPropertySetInfo->hasPropertyByName( sStyleFamilies ) ) + { + Sequence<sal_Int32> aStyleFamilies; + Sequence<OUString> aStyleNames; + mxAutoStylePool->GetRegisteredNames( aStyleFamilies, aStyleNames ); + mxExportInfo->setPropertyValue( sStyleNames, Any( aStyleNames ) ); + mxExportInfo->setPropertyValue( sStyleFamilies, + Any( aStyleFamilies ) ); + } +} + +void SvXMLExport::ImplExportAutoStyles() +{ + // transfer style names (+ families) FROM other components (if appropriate) + OUString sStyleNames( "StyleNames" ); + OUString sStyleFamilies( "StyleFamilies" ); + if( ( !( mnExportFlags & SvXMLExportFlags::STYLES ) ) + && mxExportInfo.is() + && mxExportInfo->getPropertySetInfo()->hasPropertyByName( sStyleNames ) + && mxExportInfo->getPropertySetInfo()->hasPropertyByName( sStyleFamilies ) ) + { + Sequence<sal_Int32> aStyleFamilies; + mxExportInfo->getPropertyValue( sStyleFamilies ) >>= aStyleFamilies; + Sequence<OUString> aStyleNames; + mxExportInfo->getPropertyValue( sStyleNames ) >>= aStyleNames; + mxAutoStylePool->RegisterNames( aStyleFamilies, aStyleNames ); + } + + { + // <style:automatic-styles> + SvXMLElementExport aElem( *this, XML_NAMESPACE_OFFICE, + XML_AUTOMATIC_STYLES, true, true ); + + ExportAutoStyles_(); + } +} + +void SvXMLExport::ImplExportMasterStyles() +{ + // <style:master-styles> + SvXMLElementExport aElem( *this, XML_NAMESPACE_OFFICE, XML_MASTER_STYLES, + true, true ); + + ExportMasterStyles_(); +} + +void SvXMLExport::ImplExportContent() +{ + CheckAttrList(); + + { + SvXMLElementExport aElement( *this, XML_NAMESPACE_OFFICE, XML_BODY, + true, true ); + { + XMLTokenEnum eClass = meClass; + if( XML_TEXT_GLOBAL == eClass ) + { + AddAttribute( XML_NAMESPACE_TEXT, XML_GLOBAL, + GetXMLToken( XML_TRUE ) ); + eClass = XML_TEXT; + } + if ( XML_GRAPHICS == eClass ) + eClass = XML_DRAWING; + // <office:body ...> + SetBodyAttributes(); + SvXMLElementExport aElem( *this, meClass != XML_TOKEN_INVALID, + XML_NAMESPACE_OFFICE, eClass, + true, true ); + + ExportContent_(); + } + } +} + +void SvXMLExport::SetBodyAttributes() +{ +} + +static void +lcl_AddGrddl(SvXMLExport const & rExport, const SvXMLExportFlags /*nExportMode*/) +{ + // check version >= 1.2 + switch (rExport.getSaneDefaultVersion()) { + case SvtSaveOptions::ODFSVER_011: // fall through + case SvtSaveOptions::ODFSVER_010: return; + default: break; + } + + // #i115030#: disabled, the XSLT is not finished, and not available via HTTP +#if 0 + if (SvXMLExportFlags::SETTINGS != nExportMode) // meta, content, styles + { + rExport.AddAttribute( XML_NAMESPACE_GRDDL, XML_TRANSFORMATION, + OUString("http://FIXME") ); + } +#endif +} + +void SvXMLExport::addChaffWhenEncryptedStorage() +{ + uno::Reference< embed::XEncryptionProtectedSource2 > xEncr(mpImpl->mxTargetStorage, uno::UNO_QUERY); + + if (xEncr.is() && xEncr->hasEncryptionData() && mxExtHandler.is()) + { + mxExtHandler->comment(OStringToOUString(comphelper::xml::makeXMLChaff(), RTL_TEXTENCODING_ASCII_US)); + } +} + +auto SvXMLExport::GetODFVersionAttributeValue() const -> char const* +{ + char const* pVersion(nullptr); + switch (getSaneDefaultVersion()) + { + case SvtSaveOptions::ODFSVER_013_EXTENDED: [[fallthrough]]; + case SvtSaveOptions::ODFSVER_013: pVersion = "1.3"; break; + case SvtSaveOptions::ODFSVER_012_EXTENDED: [[fallthrough]]; + case SvtSaveOptions::ODFSVER_012_EXT_COMPAT: [[fallthrough]]; + case SvtSaveOptions::ODFSVER_012: pVersion = "1.2"; break; + case SvtSaveOptions::ODFSVER_011: pVersion = "1.1"; break; + case SvtSaveOptions::ODFSVER_010: break; + + default: + assert(!"xmloff::SvXMLExport::exportDoc(), unexpected odf default version!"); + } + return pVersion; +} + +ErrCode SvXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass ) +{ + bool bOwnGraphicResolver = false; + bool bOwnEmbeddedResolver = false; + + if (!mxGraphicStorageHandler.is() || !mxEmbeddedResolver.is()) + { + Reference< XMultiServiceFactory > xFactory( mxModel, UNO_QUERY ); + if( xFactory.is() ) + { + try + { + if (!mxGraphicStorageHandler.is()) + { + mxGraphicStorageHandler.set(xFactory->createInstance( "com.sun.star.document.ExportGraphicStorageHandler"), UNO_QUERY); + bOwnGraphicResolver = mxGraphicStorageHandler.is(); + } + + if( !mxEmbeddedResolver.is() ) + { + mxEmbeddedResolver.set( + xFactory->createInstance( "com.sun.star.document.ExportEmbeddedObjectResolver" ), UNO_QUERY); + bOwnEmbeddedResolver = mxEmbeddedResolver.is(); + } + } + catch(const css::uno::Exception&) + { + } + } + } + if( (getExportFlags() & SvXMLExportFlags::OASIS) == SvXMLExportFlags::NONE ) + { + try + { + static ::comphelper::PropertyMapEntry const aInfoMap[] = + { + { OUString("Class"), 0, + ::cppu::UnoType<OUString>::get(), + PropertyAttribute::MAYBEVOID, 0}, + }; + Reference< XPropertySet > xConvPropSet( + ::comphelper::GenericPropertySet_CreateInstance( + new ::comphelper::PropertySetInfo( aInfoMap ) ) ); + + xConvPropSet->setPropertyValue( "Class", Any(GetXMLToken( eClass )) ); + + Reference< XPropertySet > xPropSet = + mxExportInfo.is() + ? PropertySetMerger_CreateInstance( mxExportInfo, + xConvPropSet ) + : xConvPropSet; + + Sequence<Any> aArgs{ Any(mxHandler), Any(xPropSet), Any(mxModel) }; + // get filter component + Reference< xml::sax::XDocumentHandler > xTmpDocHandler( + m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.comp.Oasis2OOoTransformer", aArgs, m_xContext), + UNO_QUERY); + SAL_WARN_IF(!xTmpDocHandler.is(), "xmloff.core", "can't instantiate OASIS transformer component" ); + if( xTmpDocHandler.is() ) + { + mxHandler = xTmpDocHandler; + mxExtHandler.set( mxHandler, UNO_QUERY ); + } + } + catch(const css::uno::Exception&) + { + } + } + + mxHandler->startDocument(); + + addChaffWhenEncryptedStorage(); + + // <office:document ...> + CheckAttrList(); + + // namespace attributes + // ( The namespace decls should be first attributes in the element; + // some faulty XML parsers (JAXP1.1) have a problem with this, + // also it's more elegant ) + sal_uInt16 nPos = mpNamespaceMap->GetFirstKey(); + while( USHRT_MAX != nPos ) + { + mxAttrList->AddAttribute( mpNamespaceMap->GetAttrNameByKey( nPos ), + mpNamespaceMap->GetNameByKey( nPos ) ); + nPos = mpNamespaceMap->GetNextKey( nPos ); + } + + // office:version = ... + const char*const pVersion = GetODFVersionAttributeValue(); + + if (pVersion) + { + AddAttribute( XML_NAMESPACE_OFFICE, XML_VERSION, + OUString::createFromAscii(pVersion) ); + } + + { + enum XMLTokenEnum eRootService = XML_TOKEN_INVALID; + const SvXMLExportFlags nExportMode = mnExportFlags & (SvXMLExportFlags::META|SvXMLExportFlags::STYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SETTINGS); + + lcl_AddGrddl(*this, nExportMode); + + if( SvXMLExportFlags::META == nExportMode ) + { + // export only meta + eRootService = XML_DOCUMENT_META; + } + else if ( SvXMLExportFlags::SETTINGS == nExportMode ) + { + // export only settings + eRootService = XML_DOCUMENT_SETTINGS; + } + else if( SvXMLExportFlags::STYLES == nExportMode ) + { + // export only styles + eRootService = XML_DOCUMENT_STYLES; + } + else if( SvXMLExportFlags::CONTENT == nExportMode ) + { + // export only content + eRootService = XML_DOCUMENT_CONTENT; + } + else + { + // the god'ol one4all element + eRootService = XML_DOCUMENT; + // office:mimetype = ... (only for stream containing the content) + if( eClass != XML_TOKEN_INVALID ) + { + OUString aTmp = "application/vnd.oasis.opendocument." + GetXMLToken( eClass ); + AddAttribute( XML_NAMESPACE_OFFICE, XML_MIMETYPE, aTmp ); + } + } + + SvXMLElementExport aElem( *this, XML_NAMESPACE_OFFICE, eRootService, true, true ); + + // meta information + if( mnExportFlags & SvXMLExportFlags::META ) + ImplExportMeta(); + + // settings + if( mnExportFlags & SvXMLExportFlags::SETTINGS ) + ImplExportSettings(); + + // scripts + if( mnExportFlags & SvXMLExportFlags::SCRIPTS ) + ExportScripts_(); + + // font declarations + if( mnExportFlags & SvXMLExportFlags::FONTDECLS ) + ExportFontDecls_(); + + // styles + if( mnExportFlags & SvXMLExportFlags::STYLES ) + ImplExportStyles(); + + // autostyles + if( mnExportFlags & SvXMLExportFlags::AUTOSTYLES ) + ImplExportAutoStyles(); + + // masterstyles + if( mnExportFlags & SvXMLExportFlags::MASTERSTYLES ) + ImplExportMasterStyles(); + + // content + if( mnExportFlags & SvXMLExportFlags::CONTENT ) + ImplExportContent(); + } + + mxHandler->endDocument(); + + if( bOwnGraphicResolver ) + { + uno::Reference<XComponent> xComp(mxGraphicStorageHandler, UNO_QUERY); + xComp->dispose(); + } + + if( bOwnEmbeddedResolver ) + { + Reference< XComponent > xComp( mxEmbeddedResolver, UNO_QUERY ); + xComp->dispose(); + } + + return ERRCODE_NONE; +} + +void SvXMLExport::ResetNamespaceMap() +{ + mpNamespaceMap->Clear(); +} + +OUString const & SvXMLExport::GetSourceShellID() const +{ + return mpImpl->maSrcShellID; +} + +OUString const & SvXMLExport::GetDestinationShellID() const +{ + return mpImpl->maDestShellID; +} + +void SvXMLExport::ExportMeta_() +{ + OUString generator( ::utl::DocInfoHelper::GetGeneratorString() ); + Reference< XDocumentPropertiesSupplier > xDocPropsSupplier(mxModel, + UNO_QUERY); + if (xDocPropsSupplier.is()) { + Reference<XDocumentProperties> xDocProps( + xDocPropsSupplier->getDocumentProperties()); + if (!xDocProps.is()) throw; + // update generator here + xDocProps->setGenerator(generator); + rtl::Reference<SvXMLMetaExport> pMeta = new SvXMLMetaExport(*this, xDocProps); + pMeta->Export(); + } else { + // office:meta + SvXMLElementExport aElem( *this, XML_NAMESPACE_OFFICE, XML_META, + true, true ); + { + // BM: #i60323# export generator even if xInfoProp is empty (which is the + // case for charts). The generator does not depend on xInfoProp + SvXMLElementExport anElem( *this, XML_NAMESPACE_META, XML_GENERATOR, + true, true ); + Characters(generator); + } + } +} + +void SvXMLExport::ExportScripts_() +{ + SvXMLElementExport aElement( *this, XML_NAMESPACE_OFFICE, XML_SCRIPTS, true, true ); + + // export Basic macros (only for FlatXML) + if ( mnExportFlags & SvXMLExportFlags::EMBEDDED ) + { + OUString aValue( GetNamespaceMap().GetPrefixByKey( XML_NAMESPACE_OOO ) + ":Basic" ); + AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, aValue ); + + SvXMLElementExport aElem( *this, XML_NAMESPACE_OFFICE, XML_SCRIPT, true, true ); + + // initialize Basic + if ( mxModel.is() ) + { + Reference< beans::XPropertySet > xPSet( mxModel, UNO_QUERY ); + if ( xPSet.is() ) + xPSet->getPropertyValue("BasicLibraries"); + } + + Reference < XDocumentHandler > xHdl( new XMLBasicExportFilter( mxHandler ) ); + Reference< document::XXMLBasicExporter > xExporter = document::XMLOasisBasicExporter::createWithHandler( m_xContext, xHdl ); + + xExporter->setSourceDocument( mxModel ); + Sequence< PropertyValue > aMediaDesc( 0 ); + xExporter->filter( aMediaDesc ); + } + + // export document events + Reference< document::XEventsSupplier > xEvents( GetModel(), UNO_QUERY ); + GetEventExport().Export( xEvents ); +} + +void SvXMLExport::ExportFontDecls_() +{ + if( mxFontAutoStylePool.is() ) + mxFontAutoStylePool->exportXML(); +} + +void SvXMLExport::ExportStyles_( bool ) +{ + uno::Reference< lang::XMultiServiceFactory > xFact( GetModel(), uno::UNO_QUERY ); + if( !xFact.is()) + return; + + // export (fill-)gradient-styles + try + { + uno::Reference< container::XNameAccess > xGradient( xFact->createInstance("com.sun.star.drawing.GradientTable"), uno::UNO_QUERY ); + if( xGradient.is() ) + { + XMLGradientStyleExport aGradientStyle( *this ); + + if( xGradient->hasElements() ) + { + const uno::Sequence< OUString > aNamesSeq ( xGradient->getElementNames() ); + for( const OUString& rStrName : aNamesSeq ) + { + try + { + uno::Any aValue = xGradient->getByName( rStrName ); + + aGradientStyle.exportXML( rStrName, aValue ); + } + catch(const container::NoSuchElementException&) + { + } + } + } + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } + + // export (fill-)hatch-styles + try + { + uno::Reference< container::XNameAccess > xHatch( xFact->createInstance("com.sun.star.drawing.HatchTable"), uno::UNO_QUERY ); + if( xHatch.is() ) + { + XMLHatchStyleExport aHatchStyle( *this ); + + if( xHatch->hasElements() ) + { + const uno::Sequence< OUString > aNamesSeq ( xHatch->getElementNames() ); + for( const OUString& rStrName : aNamesSeq ) + { + try + { + uno::Any aValue = xHatch->getByName( rStrName ); + + aHatchStyle.exportXML( rStrName, aValue ); + } + catch(const container::NoSuchElementException&) + {} + } + } + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } + + // export (fill-)bitmap-styles + try + { + uno::Reference< container::XNameAccess > xBitmap( xFact->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY ); + if( xBitmap.is() ) + { + if( xBitmap->hasElements() ) + { + const uno::Sequence< OUString > aNamesSeq ( xBitmap->getElementNames() ); + for( const OUString& rStrName : aNamesSeq ) + { + try + { + uno::Any aValue = xBitmap->getByName( rStrName ); + + XMLImageStyle::exportXML( rStrName, aValue, *this ); + } + catch(const container::NoSuchElementException&) + { + } + } + } + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } + + // export transparency-gradient -styles + try + { + uno::Reference< container::XNameAccess > xTransGradient( xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY ); + if( xTransGradient.is() ) + { + XMLTransGradientStyleExport aTransGradientstyle( *this ); + + if( xTransGradient->hasElements() ) + { + const uno::Sequence< OUString > aNamesSeq ( xTransGradient->getElementNames() ); + for( const OUString& rStrName : aNamesSeq ) + { + try + { + uno::Any aValue = xTransGradient->getByName( rStrName ); + + aTransGradientstyle.exportXML( rStrName, aValue ); + } + catch(const container::NoSuchElementException&) + { + } + } + } + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } + + // export marker-styles + try + { + uno::Reference< container::XNameAccess > xMarker( xFact->createInstance("com.sun.star.drawing.MarkerTable"), uno::UNO_QUERY ); + if( xMarker.is() ) + { + XMLMarkerStyleExport aMarkerStyle( *this ); + + if( xMarker->hasElements() ) + { + const uno::Sequence< OUString > aNamesSeq ( xMarker->getElementNames() ); + for( const OUString& rStrName : aNamesSeq ) + { + try + { + uno::Any aValue = xMarker->getByName( rStrName ); + + aMarkerStyle.exportXML( rStrName, aValue ); + } + catch(const container::NoSuchElementException&) + { + } + } + } + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } + + // export dash-styles + try + { + uno::Reference< container::XNameAccess > xDashes( xFact->createInstance("com.sun.star.drawing.DashTable"), uno::UNO_QUERY ); + if( xDashes.is() ) + { + XMLDashStyleExport aDashStyle( *this ); + + if( xDashes->hasElements() ) + { + const uno::Sequence< OUString > aNamesSeq ( xDashes->getElementNames() ); + for( const OUString& rStrName : aNamesSeq ) + { + try + { + uno::Any aValue = xDashes->getByName( rStrName ); + + aDashStyle.exportXML( rStrName, aValue ); + } + catch(const container::NoSuchElementException&) + { + } + } + } + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } +} + +XMLTextParagraphExport* SvXMLExport::CreateTextParagraphExport() +{ + return new XMLTextParagraphExport( *this, *GetAutoStylePool() ); +} + +XMLShapeExport* SvXMLExport::CreateShapeExport() +{ + return new XMLShapeExport(*this); +} + +SvXMLAutoStylePoolP* SvXMLExport::CreateAutoStylePool() +{ + return new SvXMLAutoStylePoolP(*this); +} + +void SvXMLExport::collectAutoStyles() +{ +} + +XMLPageExport* SvXMLExport::CreatePageExport() +{ + return new XMLPageExport( *this ); +} + +SchXMLExportHelper* SvXMLExport::CreateChartExport() +{ +// WASM_CHART change +// TODO: With Chart extracted this cannot really happen since +// no Chart could've been added at all +#if !ENABLE_WASM_STRIP_CHART + return new SchXMLExportHelper(*this, *GetAutoStylePool()); +#else + return nullptr; +#endif +} + +XMLFontAutoStylePool* SvXMLExport::CreateFontAutoStylePool() +{ + return new XMLFontAutoStylePool( *this ); +} + +xmloff::OFormLayerXMLExport* SvXMLExport::CreateFormExport() +{ + return new xmloff::OFormLayerXMLExport(*this); +} + +void SvXMLExport::GetViewSettingsAndViews(uno::Sequence<beans::PropertyValue>& rProps) +{ + GetViewSettings(rProps); + uno::Reference<document::XViewDataSupplier> xViewDataSupplier(GetModel(), uno::UNO_QUERY); + if(!xViewDataSupplier.is()) + return; + + uno::Reference<container::XIndexAccess> xIndexAccess; + xViewDataSupplier->setViewData( xIndexAccess ); // make sure we get a newly created sequence + { + // tdf#130559: don't export preview view data if active + static constexpr OUStringLiteral sNoPreviewData = u"NoPreviewData"; + css::uno::ContextLayer layer(comphelper::NewFlagContext(sNoPreviewData)); + xIndexAccess = xViewDataSupplier->getViewData(); + } + bool bAdd = false; + uno::Any aAny; + if(xIndexAccess.is() && xIndexAccess->hasElements() ) + { + sal_Int32 nCount = xIndexAccess->getCount(); + for (sal_Int32 i = 0; i < nCount; i++) + { + aAny = xIndexAccess->getByIndex(i); + uno::Sequence<beans::PropertyValue> aProps; + if( aAny >>= aProps ) + { + if( aProps.hasElements() ) + { + bAdd = true; + break; + } + } + } + } + + if( bAdd ) + { + sal_Int32 nOldLength(rProps.getLength()); + rProps.realloc(nOldLength + 1); + rProps.getArray()[nOldLength] = comphelper::makePropertyValue("Views", xIndexAccess); + } +} + +void SvXMLExport::GetViewSettings(uno::Sequence<beans::PropertyValue>&) +{ +} + +void SvXMLExport::GetConfigurationSettings(uno::Sequence<beans::PropertyValue>&) +{ +} + +sal_Int32 SvXMLExport::GetDocumentSpecificSettings( ::std::vector< SettingsGroup >& ) +{ + return 0; +} + +void SvXMLExport::collectDataStyles(bool bFromUsedStyles) +{ + Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(GetModel(), uno::UNO_QUERY); + if (!xStyleFamiliesSupplier.is()) + return; + + Reference<container::XNameAccess> xStylesFamilies(xStyleFamiliesSupplier->getStyleFamilies()); + if (!xStylesFamilies.is()) + return; + + Reference<container::XIndexAccess> xCellStyles(xStylesFamilies->getByName("CellStyles"), uno::UNO_QUERY); + if (!xCellStyles.is()) + return; + + sal_Int32 nCount(xCellStyles->getCount()); + for (sal_Int32 i = 0; i < nCount; ++i) + { + Reference<style::XStyle> xStyle(xCellStyles->getByIndex(i), uno::UNO_QUERY); + if (bFromUsedStyles && !xStyle->isInUse()) + continue; + + Reference<beans::XPropertySet> xCellProperties(xStyle, uno::UNO_QUERY); + if (xCellProperties.is()) + { + sal_Int32 nNumberFormat = 0; + if (xCellProperties->getPropertyValue("NumberFormat") >>= nNumberFormat) + addDataStyle(nNumberFormat); + } + } +} + +void SvXMLExport::addDataStyle(const sal_Int32 nNumberFormat, bool /*bTimeFormat*/ ) +{ + if(mpNumExport) + mpNumExport->SetUsed(nNumberFormat); +} + +void SvXMLExport::exportDataStyles() +{ + if(mpNumExport) + mpNumExport->Export(false); +} + +void SvXMLExport::exportAutoDataStyles() +{ + if(mpNumExport) + mpNumExport->Export(true); + + if (mxFormExport.is()) + mxFormExport->exportAutoControlNumberStyles(); +} + +OUString SvXMLExport::getDataStyleName(const sal_Int32 nNumberFormat, bool /*bTimeFormat*/ ) const +{ + OUString sTemp; + if(mpNumExport) + sTemp = mpNumExport->GetStyleName(nNumberFormat); + return sTemp; +} + +void SvXMLExport::exportAnnotationMeta(const uno::Reference<drawing::XShape>&) +{ +} + +sal_Int32 SvXMLExport::dataStyleForceSystemLanguage(sal_Int32 nFormat) const +{ + return ( mpNumExport != nullptr ) + ? mpNumExport->ForceSystemLanguage( nFormat ) : nFormat; +} + +OUString SvXMLExport::AddEmbeddedXGraphic(uno::Reference<graphic::XGraphic> const & rxGraphic, OUString & rOutMimeType, OUString const & rRequestedName) +{ + OUString sURL; + + Graphic aGraphic(rxGraphic); + OUString aOriginURL = aGraphic.getOriginURL(); + + if (!aOriginURL.isEmpty()) + { + sURL = GetRelativeReference(aOriginURL); + } + else + { + if (mxGraphicStorageHandler.is()) + { + if (!(getExportFlags() & SvXMLExportFlags::EMBEDDED)) + sURL = mxGraphicStorageHandler->saveGraphicByName(rxGraphic, rOutMimeType, rRequestedName); + } + } + return sURL; +} + +bool SvXMLExport::GetGraphicMimeTypeFromStream(uno::Reference<graphic::XGraphic> const & rxGraphic, OUString & rOutMimeType) +{ + if (mxGraphicStorageHandler.is()) + { + Reference<XInputStream> xInputStream(mxGraphicStorageHandler->createInputStream(rxGraphic)); + if (xInputStream.is()) + { + rOutMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForImageStream(xInputStream); + return true; + } + } + + return false; +} + +bool SvXMLExport::AddEmbeddedXGraphicAsBase64(uno::Reference<graphic::XGraphic> const & rxGraphic) +{ + if ((getExportFlags() & SvXMLExportFlags::EMBEDDED) && + mxGraphicStorageHandler.is()) + { + Reference<XInputStream> xInputStream(mxGraphicStorageHandler->createInputStream(rxGraphic)); + if (xInputStream.is()) + { + Graphic aGraphic(rxGraphic); + if (aGraphic.getOriginURL().isEmpty()) // don't add the base64 if the origin URL is set (image is from an external URL) + { + XMLBase64Export aBase64Exp(*this); + return aBase64Exp.exportOfficeBinaryDataElement(xInputStream); + } + } + } + + return false; +} + +OUString SvXMLExport::AddEmbeddedObject( const OUString& rEmbeddedObjectURL ) +{ + OUString sRet; + bool bSupportedURL = rEmbeddedObjectURL.startsWith(XML_EMBEDDEDOBJECT_URL_BASE) || + rEmbeddedObjectURL.startsWith(XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE); + if (bSupportedURL && mxEmbeddedResolver.is()) + { + sRet = mxEmbeddedResolver->resolveEmbeddedObjectURL(rEmbeddedObjectURL); + } + else + sRet = GetRelativeReference( rEmbeddedObjectURL ); + + return sRet; +} + +bool SvXMLExport::AddEmbeddedObjectAsBase64( const OUString& rEmbeddedObjectURL ) +{ + bool bRet = false; + bool bSupportedURL = rEmbeddedObjectURL.startsWith(XML_EMBEDDEDOBJECT_URL_BASE) || + rEmbeddedObjectURL.startsWith(XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE); + if (bSupportedURL && mxEmbeddedResolver.is()) + { + Reference < XNameAccess > xNA( mxEmbeddedResolver, UNO_QUERY ); + if( xNA.is() ) + { + Any aAny = xNA->getByName( rEmbeddedObjectURL ); + Reference < XInputStream > xIn; + aAny >>= xIn; + if( xIn.is() ) + { + XMLBase64Export aBase64Exp( *this ); + bRet = aBase64Exp.exportOfficeBinaryDataElement( xIn ); + } + } + } + + return bRet; +} + +OUString SvXMLExport::EncodeStyleName( + const OUString& rName, + bool *pEncoded ) const +{ + return GetMM100UnitConverter().encodeStyleName( rName, pEncoded ); +} + +ProgressBarHelper* SvXMLExport::GetProgressBarHelper() +{ + if (!mpProgressBarHelper) + { + mpProgressBarHelper.reset( new ProgressBarHelper(mxStatusIndicator, true) ); + + if (mxExportInfo.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxExportInfo->getPropertySetInfo(); + if (xPropertySetInfo.is()) + { + OUString sProgressRange(XML_PROGRESSRANGE); + OUString sProgressMax(XML_PROGRESSMAX); + OUString sProgressCurrent(XML_PROGRESSCURRENT); + OUString sRepeat(XML_PROGRESSREPEAT); + if (xPropertySetInfo->hasPropertyByName(sProgressMax) && + xPropertySetInfo->hasPropertyByName(sProgressCurrent) && + xPropertySetInfo->hasPropertyByName(sProgressRange)) + { + uno::Any aAny; + sal_Int32 nProgressMax(0); + sal_Int32 nProgressCurrent(0); + sal_Int32 nProgressRange(0); + aAny = mxExportInfo->getPropertyValue(sProgressRange); + if (aAny >>= nProgressRange) + mpProgressBarHelper->SetRange(nProgressRange); + aAny = mxExportInfo->getPropertyValue(sProgressMax); + if (aAny >>= nProgressMax) + mpProgressBarHelper->SetReference(nProgressMax); + aAny = mxExportInfo->getPropertyValue(sProgressCurrent); + if (aAny >>= nProgressCurrent) + mpProgressBarHelper->SetValue(nProgressCurrent); + } + if (xPropertySetInfo->hasPropertyByName(sRepeat)) + { + uno::Any aAny = mxExportInfo->getPropertyValue(sRepeat); + if (aAny.getValueType() == cppu::UnoType<bool>::get()) + mpProgressBarHelper->SetRepeat(::cppu::any2bool(aAny)); + else { + SAL_WARN("xmloff.core", "why is it no boolean?" ); + } + } + } + } + } + return mpProgressBarHelper.get(); +} + +XMLEventExport& SvXMLExport::GetEventExport() +{ + if( nullptr == mpEventExport) + { + // create EventExport on demand + mpEventExport.reset( new XMLEventExport(*this) ); + + // and register standard handlers + names + mpEventExport->AddHandler("StarBasic", std::make_unique<XMLStarBasicExportHandler>()); + mpEventExport->AddHandler("Script", std::make_unique<XMLScriptExportHandler>()); + mpEventExport->AddTranslationTable(aStandardEventTable); + } + + return *mpEventExport; +} + +XMLImageMapExport& SvXMLExport::GetImageMapExport() +{ + // image map export, create on-demand + if( nullptr == mpImageMapExport ) + { + mpImageMapExport.reset( new XMLImageMapExport(*this) ); + } + + return *mpImageMapExport; +} + +// XUnoTunnel & co +UNO3_GETIMPLEMENTATION_IMPL(SvXMLExport); + +void SvXMLExport::ExportEmbeddedOwnObject( Reference< XComponent > const & rComp ) +{ + OUString sFilterService; + + Reference < lang::XServiceInfo > xServiceInfo( rComp, UNO_QUERY ); + if( xServiceInfo.is() ) + { + for (const auto& [sModelService, sMatchingFilterService] : aServiceMap) + { + if( xServiceInfo->supportsService( sModelService ) ) + { + sFilterService = sMatchingFilterService; + break; + } + } + } + + SAL_WARN_IF( !sFilterService.getLength(), "xmloff.core", "no export filter for own object" ); + + if( sFilterService.isEmpty() ) + return; + + Reference < XDocumentHandler > xHdl = + new XMLEmbeddedObjectExportFilter( mxHandler ); + + Sequence < Any > aArgs{ Any(xHdl) }; + Reference< document::XExporter > xExporter( + m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(sFilterService, aArgs, m_xContext), + UNO_QUERY); + SAL_WARN_IF( !xExporter.is(), "xmloff.core", "can't instantiate export filter component for own object" ); + if( !xExporter.is() ) + return; + + xExporter->setSourceDocument( rComp ); + + Reference<XFilter> xFilter( xExporter, UNO_QUERY ); + + Sequence < PropertyValue > aMediaDesc( 0 ); + xFilter->filter( aMediaDesc ); +} + +OUString SvXMLExport::GetRelativeReference(const OUString& rValue) +{ + OUString sValue( rValue ); + // #i65474# handling of fragment URLs ("#...") is undefined + // they are stored 'as is' + uno::Reference< uri::XUriReference > xUriRef; + if(!sValue.isEmpty() && sValue[0] != '#') + { + try + { + xUriRef = mpImpl->mxUriReferenceFactory->parse( rValue ); + if( xUriRef.is() && !xUriRef->isAbsolute() ) + { + //#i61943# relative URLs need special handling + INetURLObject aTemp( mpImpl->msPackageURI ); + bool bWasAbsolute = false; + sValue = aTemp.smartRel2Abs(sValue, bWasAbsolute ).GetMainURL(INetURLObject::DecodeMechanism::ToIUri); + } + } + catch(const uno::Exception&) + { + } + } + if( xUriRef.is() )//no conversion for empty values or for fragments + { + //conversion for matching schemes only + if( xUriRef->getScheme() == mpImpl->msPackageURIScheme ) + { + sValue = INetURLObject::GetRelURL( msOrigFileName, sValue ); + } + } + return sValue; +} + +void SvXMLExport::StartElement(sal_uInt16 nPrefix, + enum ::xmloff::token::XMLTokenEnum eName, + bool bIgnWSOutside ) +{ + StartElement(GetNamespaceMap_().GetQNameByKey( nPrefix, + GetXMLToken(eName) ), bIgnWSOutside); +} + +void SvXMLExport::StartElement(const OUString& rName, + bool bIgnWSOutside ) +{ + if ((mnErrorFlags & SvXMLErrorFlags::DO_NOTHING) != SvXMLErrorFlags::DO_NOTHING) + { + try + { + if( bIgnWSOutside && ((mnExportFlags & SvXMLExportFlags::PRETTY) == SvXMLExportFlags::PRETTY)) + mxHandler->ignorableWhitespace( msWS ); + mxHandler->startElement( rName, GetXAttrList() ); + } + catch (const SAXInvalidCharacterException& e) + { + Sequence<OUString> aPars { rName }; + SetError( XMLERROR_SAX|XMLERROR_FLAG_WARNING, aPars, e.Message, nullptr ); + } + catch (const SAXException& e) + { + Sequence<OUString> aPars { rName }; + SetError( XMLERROR_SAX|XMLERROR_FLAG_ERROR|XMLERROR_FLAG_SEVERE, + aPars, e.Message, nullptr ); + } + } + ClearAttrList(); + ++mpImpl->mDepth; // increment nesting depth counter +} + +void SvXMLExport::Characters(const OUString& rChars) +{ + if ((mnErrorFlags & SvXMLErrorFlags::DO_NOTHING) == SvXMLErrorFlags::DO_NOTHING) + return; + + try + { + mxHandler->characters(rChars); + } + catch (const SAXInvalidCharacterException& e) + { + Sequence<OUString> aPars { rChars }; + SetError( XMLERROR_SAX|XMLERROR_FLAG_WARNING, aPars, e.Message, nullptr ); + } + catch (const SAXException& e) + { + Sequence<OUString> aPars { rChars }; + SetError( XMLERROR_SAX|XMLERROR_FLAG_ERROR|XMLERROR_FLAG_SEVERE, + aPars, e.Message, nullptr ); + } +} + +void SvXMLExport::EndElement(sal_uInt16 nPrefix, + enum ::xmloff::token::XMLTokenEnum eName, + bool bIgnWSInside ) +{ + EndElement(GetNamespaceMap_().GetQNameByKey( nPrefix, GetXMLToken(eName) ), + bIgnWSInside); +} + +void SvXMLExport::EndElement(const OUString& rName, + bool bIgnWSInside ) +{ + // decrement nesting depth counter & (maybe) restore namespace map + --mpImpl->mDepth; + if (!mpImpl->mNamespaceMaps.empty() && + (mpImpl->mNamespaceMaps.top().second == mpImpl->mDepth)) + { + mpNamespaceMap = std::move(mpImpl->mNamespaceMaps.top().first); + mpImpl->mNamespaceMaps.pop(); + } + SAL_WARN_IF(!mpImpl->mNamespaceMaps.empty() && + (mpImpl->mNamespaceMaps.top().second >= mpImpl->mDepth), "xmloff.core", "SvXMLExport: NamespaceMaps corrupted"); + + if ((mnErrorFlags & SvXMLErrorFlags::DO_NOTHING) == SvXMLErrorFlags::DO_NOTHING) + return; + + try + { + if( bIgnWSInside && ((mnExportFlags & SvXMLExportFlags::PRETTY) == SvXMLExportFlags::PRETTY)) + mxHandler->ignorableWhitespace( msWS ); + mxHandler->endElement( rName ); + } + catch (const SAXException& e) + { + Sequence<OUString> aPars { rName }; + SetError( XMLERROR_SAX|XMLERROR_FLAG_ERROR|XMLERROR_FLAG_SEVERE, + aPars, e.Message, nullptr ); + } +} + +void SvXMLExport::IgnorableWhitespace() +{ + if ((mnExportFlags & SvXMLExportFlags::PRETTY) != SvXMLExportFlags::PRETTY) + return; + + if ((mnErrorFlags & SvXMLErrorFlags::DO_NOTHING) == SvXMLErrorFlags::DO_NOTHING) + return; + + try + { + mxHandler->ignorableWhitespace( msWS ); + } + catch (const SAXException& e) + { + SetError( XMLERROR_SAX|XMLERROR_FLAG_ERROR|XMLERROR_FLAG_SEVERE, + {}, e.Message, nullptr ); + } +} + +void SvXMLExport::SetError( + sal_Int32 nId, + const Sequence<OUString>& rMsgParams, + const OUString& rExceptionMessage, + const Reference<XLocator>& rLocator ) +{ + // allow multi-threaded access to the cancel() method + static std::mutex aMutex; + std::scoped_lock aGuard(aMutex); + + // maintain error flags + if ( ( nId & XMLERROR_FLAG_ERROR ) != 0 ) + mnErrorFlags |= SvXMLErrorFlags::ERROR_OCCURRED; + if ( ( nId & XMLERROR_FLAG_WARNING ) != 0 ) + mnErrorFlags |= SvXMLErrorFlags::WARNING_OCCURRED; + if ( ( nId & XMLERROR_FLAG_SEVERE ) != 0 ) + mnErrorFlags |= SvXMLErrorFlags::DO_NOTHING; + + // create error list on demand + if ( mpXMLErrors == nullptr ) + mpXMLErrors.reset( new XMLErrors() ); + + // save error information + mpXMLErrors->AddRecord( nId, rMsgParams, rExceptionMessage, rLocator ); +} + +void SvXMLExport::SetError( + sal_Int32 nId, + const Sequence<OUString>& rMsgParams) +{ + SetError( nId, rMsgParams, "", nullptr ); +} + +void SvXMLExport::DisposingModel() +{ + mxModel.clear(); + // Shapes in Writer cannot be named via context menu (#i51726#) + meModelType = SvtModuleOptions::EFactory::UNKNOWN_FACTORY; + mxEventListener.clear(); +} + + +::comphelper::UnoInterfaceToUniqueIdentifierMapper& SvXMLExport::getInterfaceToIdentifierMapper() +{ + return mpImpl->maInterfaceToIdentifierMapper; +} + +// Written OpenDocument file format doesn't fit to the created text document (#i69627#) +bool SvXMLExport::writeOutlineStyleAsNormalListStyle() const +{ + return mpImpl->mbOutlineStyleAsNormalListStyle; +} + +uno::Reference< embed::XStorage > const & SvXMLExport::GetTargetStorage() const +{ + return mpImpl->mxTargetStorage; +} + +SvtSaveOptions::ODFSaneDefaultVersion SvXMLExport::getSaneDefaultVersion() const +{ + if (mpImpl->m_oOverrideODFVersion) + { + return *mpImpl->m_oOverrideODFVersion; + } + return GetODFSaneDefaultVersion(); +} + +void +SvXMLExport::AddAttributeIdLegacy( + sal_uInt16 const nLegacyPrefix, OUString const& rValue) +{ + switch (getSaneDefaultVersion()) { + case SvtSaveOptions::ODFSVER_011: // fall through + case SvtSaveOptions::ODFSVER_010: break; + default: // ODF 1.2: xml:id + AddAttribute(XML_NAMESPACE_XML, XML_ID, rValue); + } + // in ODF 1.1 this was form:id, anim:id, draw:id, or text:id + // backward compatibility: in ODF 1.2 write _both_ id attrs + AddAttribute(nLegacyPrefix, XML_ID, rValue); + // FIXME: this function simply assumes that rValue is unique +} + +void +SvXMLExport::AddAttributeXmlId(uno::Reference<uno::XInterface> const & i_xIfc) +{ + // check version >= 1.2 + switch (getSaneDefaultVersion()) { + case SvtSaveOptions::ODFSVER_011: // fall through + case SvtSaveOptions::ODFSVER_010: return; + default: break; + } + const uno::Reference<rdf::XMetadatable> xMeta(i_xIfc, + uno::UNO_QUERY); +//FIXME not yet... + if ( !xMeta.is() ) + return; + + const beans::StringPair mdref( xMeta->getMetadataReference() ); + if ( mdref.Second.isEmpty() ) + return; + + const OUString streamName = mpImpl->mStreamName; + if ( !streamName.isEmpty() ) + { + if ( streamName == mdref.First ) + { + AddAttribute( XML_NAMESPACE_XML, XML_ID, mdref.Second ); + } + else + { + SAL_WARN("xmloff.core","SvXMLExport::AddAttributeXmlId: invalid stream name"); + } + } + else + { + // FIXME: this is ugly + // there is no stream name (e.g. XSLT, flat-xml format)! + // but how do we ensure uniqueness in this case? + // a) just omit styles.xml ids -- they are unlikely anyway... + // b) somehow find out whether we are currently exporting styles + // or content, and prefix "s" or "c" => unique + if ( mdref.First == "content.xml" ) + { + AddAttribute( XML_NAMESPACE_XML, XML_ID, mdref.Second ); + } + else + { + SAL_INFO("xmloff.core", "SvXMLExport::AddAttributeXmlId: no stream name given: dropping styles.xml xml:id"); + } + } +} + +void +SvXMLExport::AddAttributesRDFa( + uno::Reference<text::XTextContent> const & i_xTextContent) +{ + // check version >= 1.2 + switch (getSaneDefaultVersion()) { + case SvtSaveOptions::ODFSVER_011: // fall through + case SvtSaveOptions::ODFSVER_010: return; + default: break; + } + + const uno::Reference<rdf::XMetadatable> xMeta( + i_xTextContent, uno::UNO_QUERY); + if (!xMeta.is() || xMeta->getMetadataReference().Second.isEmpty()) + { + return; // no xml:id => no RDFa + } + + if (!mpImpl->mpRDFaHelper) + { + mpImpl->mpRDFaHelper.reset( new ::xmloff::RDFaExportHelper(*this) ); + } + mpImpl->mpRDFaHelper->AddRDFa(xMeta); +} + +bool SvXMLExport::exportTextNumberElement() const +{ + return mpImpl->mbExportTextNumberElement; +} + +bool SvXMLExport::SetNullDateOnUnitConverter() +{ + // if the null date has already been set, don't set it again (performance) + if (!mpImpl->mbNullDateInitialized) + mpImpl->mbNullDateInitialized = GetMM100UnitConverter().setNullDate(GetModel()); + + return mpImpl->mbNullDateInitialized; +} + +OUString const & SvXMLExport::GetImageFilterName() const +{ + return msImgFilterName; +} + +void SvXMLElementExport::StartElement( + const sal_uInt16 nPrefixKey, + const OUString& rLName, + const bool bIgnoreWhitespaceOutside ) +{ + maElementName = mrExport.GetNamespaceMap().GetQNameByKey(nPrefixKey, rLName); + mrExport.StartElement(maElementName, bIgnoreWhitespaceOutside); +} + +SvXMLElementExport::SvXMLElementExport( + SvXMLExport& rExp, + sal_uInt16 nPrefixKey, + const char *pLName, + bool bIWSOutside, + bool bIWSInside ) + : mrExport( rExp ) + , mbIgnoreWhitespaceInside( bIWSInside ) + , mbDoSomething( true ) +{ + const OUString sLName( OUString::createFromAscii( pLName ) ); + StartElement( nPrefixKey, sLName, bIWSOutside ); +} + +SvXMLElementExport::SvXMLElementExport( + SvXMLExport& rExp, + sal_uInt16 nPrefixKey, + const OUString& rLName, + bool bIWSOutside, + bool bIWSInside ) + : mrExport( rExp ) + , mbIgnoreWhitespaceInside( bIWSInside ) + , mbDoSomething( true ) +{ + StartElement( nPrefixKey, rLName, bIWSOutside ); +} + +SvXMLElementExport::SvXMLElementExport( + SvXMLExport& rExp, + sal_uInt16 nPrefixKey, + enum XMLTokenEnum eLName, + bool bIWSOutside, + bool bIWSInside ) + : mrExport( rExp ) + , mbIgnoreWhitespaceInside( bIWSInside ) + , mbDoSomething( true ) +{ + StartElement( nPrefixKey, GetXMLToken(eLName), bIWSOutside ); +} + +SvXMLElementExport::SvXMLElementExport( + SvXMLExport& rExp, + bool bDoSth, + sal_uInt16 nPrefixKey, + enum XMLTokenEnum eLName, + bool bIWSOutside, + bool bIWSInside ) + : mrExport( rExp ) + , mbIgnoreWhitespaceInside( bIWSInside ) + , mbDoSomething( bDoSth ) +{ + if ( mbDoSomething ) + StartElement( nPrefixKey, GetXMLToken( eLName ), bIWSOutside ); +} + +SvXMLElementExport::SvXMLElementExport( + SvXMLExport& rExp, + const OUString& rQName, + bool bIWSOutside, + bool bIWSInside ) + : mrExport( rExp ) + , mbIgnoreWhitespaceInside( bIWSInside ) + , mbDoSomething( true ) +{ + maElementName = rQName; + rExp.StartElement( rQName, bIWSOutside ); +} + +SvXMLElementExport::~SvXMLElementExport() +{ + if ( mbDoSomething ) + { + mrExport.EndElement( maElementName, mbIgnoreWhitespaceInside ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |