/* -*- 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 <officecfg/Office/Common.hxx>
#include <vcl/errinf.hxx>
#include <sal/log.hxx>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/xml/sax/SAXParseException.hpp>
#include <comphelper/processfactory.hxx>
#include <comphelper/propertysequence.hxx>
#include <o3tl/string_view.hxx>
#include <editeng/outlobj.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/sfxsids.hrc>
#include <drawdoc.hxx>
#include <sdpage.hxx>
#include <Outliner.hxx>
#include <unotools/streamwrap.hxx>
#include <svx/dialmgr.hxx>
#include <svx/strings.hrc>
#include <xmloff/xmlgrhlp.hxx>
#include <xmloff/xmlexp.hxx>
#include <DrawDocShell.hxx>
#include <sdxmlwrp.hxx>
#include <svx/xmleohlp.hxx>
#include <com/sun/star/xml/sax/Parser.hpp>
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#include <com/sun/star/xml/sax/XFastParser.hpp>
#include <com/sun/star/document/XFilter.hpp>
#include <com/sun/star/document/XImporter.hpp>
#include <com/sun/star/document/XExporter.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/packages/WrongPasswordException.hpp>
#include <com/sun/star/packages/zip/ZipIOException.hpp>
#include <com/sun/star/xml/sax/InputSource.hpp>
#include <com/sun/star/xml/sax/Writer.hpp>
#include <comphelper/genericpropertyset.hxx>
#include <comphelper/propertysetinfo.hxx>
#include <editeng/eeitem.hxx>
// include necessary for XML progress bar at load time
#include <svl/itemset.hxx>
#include <svl/stritem.hxx>
#include <svtools/sfxecode.hxx>
#include <sddll.hxx>
#include <sderror.hxx>
#include <sdresid.hxx>
#include "sdtransform.hxx"
#include <strings.hrc>
#include <sfx2/frame.hxx>
#include <tools/debug.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <com/sun/star/beans/XPropertyContainer.hpp>
#include <com/sun/star/document/XDocumentProperties.hpp>
using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::document;
using namespace comphelper;
#define SD_XML_READERROR ErrCode(1234)
char const sXML_export_impress_meta_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisMetaExporter";
char const sXML_export_impress_styles_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisStylesExporter";
char const sXML_export_impress_content_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisContentExporter";
char const sXML_export_impress_settings_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisSettingsExporter";
char const sXML_export_draw_meta_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisMetaExporter";
char const sXML_export_draw_styles_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisStylesExporter";
char const sXML_export_draw_content_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisContentExporter";
char const sXML_export_draw_settings_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisSettingsExporter";
char const sXML_import_impress_meta_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisMetaImporter";
char const sXML_import_impress_styles_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisStylesImporter";
char const sXML_import_impress_content_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisContentImporter";
char const sXML_import_impress_settings_oasis_service[] = "com.sun.star.comp.Impress.XMLOasisSettingsImporter";
char const sXML_import_draw_meta_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisMetaImporter";
char const sXML_import_draw_styles_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisStylesImporter";
char const sXML_import_draw_content_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisContentImporter";
char const sXML_import_draw_settings_oasis_service[] = "com.sun.star.comp.Draw.XMLOasisSettingsImporter";
// OOo
char const sXML_import_impress_meta_ooo_service[] = "com.sun.star.comp.Impress.XMLMetaImporter";
char const sXML_import_impress_styles_ooo_service[] = "com.sun.star.comp.Impress.XMLStylesImporter";
char const sXML_import_impress_content_ooo_service[] = "com.sun.star.comp.Impress.XMLContentImporter";
char const sXML_import_impress_settings_ooo_service[] = "com.sun.star.comp.Impress.XMLSettingsImporter";
char const sXML_import_draw_meta_ooo_service[] = "com.sun.star.comp.Draw.XMLMetaImporter";
char const sXML_import_draw_styles_ooo_service[] = "com.sun.star.comp.Draw.XMLStylesImporter";
char const sXML_import_draw_content_ooo_service[] = "com.sun.star.comp.Draw.XMLContentImporter";
char const sXML_import_draw_settings_ooo_service[] = "com.sun.star.comp.Draw.XMLSettingsImporter";
namespace {
struct XML_SERVICEMAP
{
const char* mpService;
const char* mpStream;
};
struct XML_SERVICES
{
const char* mpMeta;
const char* mpStyles;
const char* mpContent;
const char* mpSettings;
};
}
static XML_SERVICES const * getServices( bool bImport, bool bDraw, sal_uLong nStoreVer )
{
// Expect that export always sets nStoreVer to SOFFICE_FILEFORMAT_8.
assert(bImport || nStoreVer != SOFFICE_FILEFORMAT_60);
static XML_SERVICES const gServices[] =
{
{ sXML_import_impress_meta_oasis_service, sXML_import_impress_styles_oasis_service, sXML_import_impress_content_oasis_service, sXML_import_impress_settings_oasis_service },
{ sXML_import_draw_meta_oasis_service, sXML_import_draw_styles_oasis_service, sXML_import_draw_content_oasis_service, sXML_import_draw_settings_oasis_service },
{ sXML_export_impress_meta_oasis_service, sXML_export_impress_styles_oasis_service, sXML_export_impress_content_oasis_service, sXML_export_impress_settings_oasis_service },
{ sXML_export_draw_meta_oasis_service, sXML_export_draw_styles_oasis_service, sXML_export_draw_content_oasis_service, sXML_export_draw_settings_oasis_service },
{ sXML_import_impress_meta_ooo_service, sXML_import_impress_styles_ooo_service, sXML_import_impress_content_ooo_service, sXML_import_impress_settings_ooo_service },
{ sXML_import_draw_meta_ooo_service, sXML_import_draw_styles_ooo_service, sXML_import_draw_content_ooo_service, sXML_import_draw_settings_ooo_service },
};
return &gServices[ (bImport ? 0 : 2) + ((nStoreVer == SOFFICE_FILEFORMAT_60) ? 4 : 0) + (bDraw ? 1 : 0 ) ];
}
SdXMLFilter::SdXMLFilter( SfxMedium& rMedium, ::sd::DrawDocShell& rDocShell, SdXMLFilterMode eFilterMode, sal_uLong nStoreVer ) :
SdFilter( rMedium, rDocShell ), meFilterMode( eFilterMode ), mnStoreVer( nStoreVer )
{
}
SdXMLFilter::~SdXMLFilter()
{
}
namespace
{
ErrCodeMsg ReadThroughComponent(
const Reference<io::XInputStream>& xInputStream,
const Reference<XComponent>& xModelComponent,
const OUString& rStreamName,
Reference<uno::XComponentContext> const & rxContext,
const char* pFilterName,
const Sequence<Any>& rFilterArguments,
const OUString& rName,
bool bMustBeSuccessful,
bool bEncrypted )
{
DBG_ASSERT(xInputStream.is(), "input stream missing");
DBG_ASSERT(xModelComponent.is(), "document missing");
DBG_ASSERT(rxContext.is(), "factory missing");
DBG_ASSERT(nullptr != pFilterName,"I need a service name for the component!");
SAL_INFO( "sd.filter", "ReadThroughComponent" );
// prepare ParserInputSource
xml::sax::InputSource aParserInput;
aParserInput.sSystemId = rName;
aParserInput.aInputStream = xInputStream;
// get filter
OUString aFilterName(OUString::createFromAscii(pFilterName));
// the underlying SvXMLImport implements XFastParser, XImporter, XFastDocumentHandler
Reference< XInterface > xFilter(
rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(aFilterName, rFilterArguments, rxContext),
UNO_QUERY );
SAL_WARN_IF(!xFilter.is(), "sd.filter", "Can't instantiate filter component: " << aFilterName);
if( !xFilter.is() )
return SD_XML_READERROR;
Reference< xml::sax::XFastParser > xFastParser(xFilter, UNO_QUERY);
Reference< xml::sax::XDocumentHandler > xDocumentHandler;
if (!xFastParser)
xDocumentHandler.set(xFilter, UNO_QUERY);
if (!xFastParser && !xDocumentHandler)
{
SAL_WARN("sd", "service does not implement XFastParser or XDocumentHandler");
assert(false);
return SD_XML_READERROR;
}
SAL_INFO( "sd.filter", "" << pFilterName << " created" );
// connect model and filter
Reference < XImporter > xImporter( xFilter, UNO_QUERY );
xImporter->setTargetDocument( xModelComponent );
// finally, parser the stream
SAL_INFO( "sd.filter", "parsing stream" );
try
{
if (xFastParser)
xFastParser->parseStream( aParserInput );
else
{
Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(rxContext);
// connect parser and filter
xParser->setDocumentHandler( xDocumentHandler );
xParser->parseStream( aParserInput );
}
}
catch (const xml::sax::SAXParseException& r)
{
css::uno::Any ex( cppu::getCaughtException() );
// sax parser sends wrapped exceptions,
// try to find the original one
xml::sax::SAXException aSaxEx = *static_cast<xml::sax::SAXException const *>(&r);
bool bTryChild = true;
while( bTryChild )
{
xml::sax::SAXException aTmp;
if ( aSaxEx.WrappedException >>= aTmp )
aSaxEx = std::move(aTmp);
else
bTryChild = false;
}
packages::zip::ZipIOException aBrokenPackage;
if ( aSaxEx.WrappedException >>= aBrokenPackage )
return ERRCODE_IO_BROKENPACKAGE;
if( bEncrypted )
return ERRCODE_SFX_WRONGPASSWORD;
SAL_WARN( "sd.filter", "SAX parse exception caught while importing: " << exceptionToString(ex));
OUString sErr = OUString::number( r.LineNumber ) +
"," + OUString::number( r.ColumnNumber );
if (!rStreamName.isEmpty())
{
return ErrCodeMsg(
(bMustBeSuccessful ? ERR_FORMAT_FILE_ROWCOL
: WARN_FORMAT_FILE_ROWCOL),
rStreamName, sErr,
DialogMask::ButtonsOk | DialogMask::MessageError );
}
else
{
DBG_ASSERT( bMustBeSuccessful, "Warnings are not supported" );
return ErrCodeMsg( ERR_FORMAT_ROWCOL, sErr,
DialogMask::ButtonsOk | DialogMask::MessageError );
}
}
catch (const xml::sax::SAXException& r)
{
css::uno::Any ex( cppu::getCaughtException() );
packages::zip::ZipIOException aBrokenPackage;
if ( r.WrappedException >>= aBrokenPackage )
return ERRCODE_IO_BROKENPACKAGE;
if( bEncrypted )
return ERRCODE_SFX_WRONGPASSWORD;
SAL_WARN( "sd.filter", "SAX exception caught while importing: " << exceptionToString(ex));
return SD_XML_READERROR;
}
catch (const packages::zip::ZipIOException&)
{
TOOLS_WARN_EXCEPTION( "sd.filter", "Zip exception caught while importing");
return ERRCODE_IO_BROKENPACKAGE;
}
catch (const io::IOException&)
{
TOOLS_WARN_EXCEPTION( "sd.filter", "IO exception caught while importing");
return SD_XML_READERROR;
}
catch (const uno::Exception&)
{
TOOLS_WARN_EXCEPTION( "sd.filter", "uno exception caught while importing");
return SD_XML_READERROR;
}
// success!
return ERRCODE_NONE;
}
ErrCodeMsg ReadThroughComponent(
const uno::Reference < embed::XStorage >& xStorage,
const Reference<XComponent>& xModelComponent,
const char* pStreamName,
Reference<uno::XComponentContext> const & rxContext,
const char* pFilterName,
const Sequence<Any>& rFilterArguments,
const OUString& rName,
bool bMustBeSuccessful )
{
DBG_ASSERT(xStorage.is(), "Need storage!");
DBG_ASSERT(nullptr != pStreamName, "Please, please, give me a name!");
// open stream (and set parser input)
OUString sStreamName = OUString::createFromAscii(pStreamName);
bool bContainsStream = false;
try
{
bContainsStream = xStorage->isStreamElement(sStreamName);
}
catch (const container::NoSuchElementException&)
{
}
if (!bContainsStream )
{
// stream name not found! return immediately with OK signal
return ERRCODE_NONE;
}
// set Base URL
uno::Reference< beans::XPropertySet > xInfoSet;
if( rFilterArguments.hasElements() )
rFilterArguments.getConstArray()[0] >>= xInfoSet;
DBG_ASSERT( xInfoSet.is(), "missing property set" );
if( xInfoSet.is() )
{
xInfoSet->setPropertyValue( u"StreamName"_ustr, Any( sStreamName ) );
}
try
{
// get input stream
Reference <io::XStream> xStream =
xStorage->openStreamElement( sStreamName, embed::ElementModes::READ );
Reference <beans::XPropertySet > xProps( xStream, uno::UNO_QUERY );
if ( !xStream.is() || ! xProps.is() )
return SD_XML_READERROR;
Any aAny = xProps->getPropertyValue( u"Encrypted"_ustr );
bool bEncrypted = false;
aAny >>= bEncrypted;
Reference <io::XInputStream> xInputStream = xStream->getInputStream();
// read from the stream
return ReadThroughComponent(
xInputStream, xModelComponent, sStreamName, rxContext,
pFilterName, rFilterArguments,
rName, bMustBeSuccessful, bEncrypted );
}
catch (const packages::WrongPasswordException&)
{
return ERRCODE_SFX_WRONGPASSWORD;
}
catch (const packages::zip::ZipIOException&)
{
return ERRCODE_IO_BROKENPACKAGE;
}
catch (const uno::Exception&)
{}
return SD_XML_READERROR;
}
}
//PresObjKind::Outlines in master pages are the preview of the outline styles
//numbering format. Since fdo#78151 toggling bullets on and off changes
//the style they are a preview of, previously toggling bullets on and off
//would only affect the preview paragraph itself without an effect on the
//style. i.e. previews of numbering which don't match the real numbering
//they are supposed to be a preview of.
//
//But there exist documents which were saved previous to that modification
//so here we detect such cases and fix them up to ensure the previews
//numbering level matches that of the outline level it previews
static void fixupOutlinePlaceholderNumberingDepths(SdDrawDocument* pDoc)
{
for (sal_uInt16 i = 0; i < pDoc->GetMasterSdPageCount(PageKind::Standard); ++i)
{
SdPage *pMasterPage = pDoc->GetMasterSdPage(i, PageKind::Standard);
SdrObject* pMasterOutline = pMasterPage->GetPresObj(PresObjKind::Outline);
if (!pMasterOutline)
continue;
OutlinerParaObject* pOutlParaObj = pMasterOutline->GetOutlinerParaObject();
if (!pOutlParaObj)
continue;
SdOutliner* pOutliner = pDoc->GetInternalOutliner();
pOutliner->Clear();
pOutliner->SetText(*pOutlParaObj);
bool bInconsistent = false;
const sal_Int32 nParaCount = pOutliner->GetParagraphCount();
for (sal_Int32 j = 0; j < nParaCount; ++j)
{
//Make sure the depth of the paragraph matches that of the outline style it previews
const sal_Int16 nExpectedDepth = j;
if (nExpectedDepth != pOutliner->GetDepth(j))
{
Paragraph* p = pOutliner->GetParagraph(j);
pOutliner->SetDepth(p, nExpectedDepth);
bInconsistent = true;
}
//If the preview has hard-coded bullets/numbering then they must
//be stripped to reveal the true underlying styles attributes
SfxItemSet aAttrs(pOutliner->GetParaAttribs(j));
if (aAttrs.GetItemState(EE_PARA_NUMBULLET) == SfxItemState::SET)
{
aAttrs.ClearItem(EE_PARA_NUMBULLET);
pOutliner->SetParaAttribs(j, aAttrs);
bInconsistent = true;
}
}
if (bInconsistent)
{
SAL_WARN("sd.filter", "Fixing inconsistent outline numbering placeholder preview");
pMasterOutline->SetOutlinerParaObject(pOutliner->CreateParaObject(0, nParaCount));
}
pOutliner->Clear();
}
}
bool SdXMLFilter::Import( ErrCode& nError )
{
ErrCodeMsg nRet = ERRCODE_NONE;
// Get service factory
const Reference< uno::XComponentContext >& rxContext =
comphelper::getProcessComponentContext();
SdDrawDocument* pDoc = mrDocShell.GetDoc();
bool const bWasUndo(pDoc->IsUndoEnabled());
pDoc->EnableUndo(false);
pDoc->NewOrLoadCompleted( DocCreationMode::New );
pDoc->CreateFirstPages();
pDoc->StopWorkStartupDelay();
mxModel->lockControllers();
/** property map for import info set */
static PropertyMapEntry const aImportInfoMap[] =
{
// necessary properties for XML progress bar at load time
{ u"ProgressRange"_ustr, 0, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
{ u"ProgressMax"_ustr, 0, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
{ u"ProgressCurrent"_ustr, 0, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
{ u"Preview"_ustr, 0, cppu::UnoType<sal_Bool>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
{ u"PageLayouts"_ustr, 0, cppu::UnoType<container::XNameAccess>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
{ u"PrivateData"_ustr, 0, cppu::UnoType<XInterface>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
{ u"BaseURI"_ustr, 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
{ u"StreamRelPath"_ustr, 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
{ u"StreamName"_ustr, 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
{ u"BuildId"_ustr, 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
{ u"OrganizerMode"_ustr, 0, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
{ u"SourceStorage"_ustr, 0, cppu::UnoType<embed::XStorage>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
};
uno::Reference< beans::XPropertySet > xInfoSet( GenericPropertySet_CreateInstance( new PropertySetInfo( aImportInfoMap ) ) );
xInfoSet->setPropertyValue( u"Preview"_ustr , uno::Any( mrDocShell.GetDoc()->IsStarDrawPreviewMode() ) );
// ---- get BuildId from parent container if available
uno::Reference< container::XChild > xChild( mxModel, uno::UNO_QUERY );
if( xChild.is() )
{
uno::Reference< beans::XPropertySet > xParentSet( xChild->getParent(), uno::UNO_QUERY );
if( xParentSet.is() )
{
uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xParentSet->getPropertySetInfo() );
OUString sPropName( u"BuildId"_ustr );
if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(sPropName) )
{
xInfoSet->setPropertyValue( sPropName, xParentSet->getPropertyValue(sPropName) );
}
}
}
uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
rtl::Reference<SvXMLGraphicHelper> xGraphicHelper;
Reference< document::XEmbeddedObjectResolver > xObjectResolver;
rtl::Reference<SvXMLEmbeddedObjectHelper> xObjectHelper;
Reference< lang::XComponent > xModelComp = mxModel;
// try to get an XStatusIndicator from the Medium
{
const SfxUnoAnyItem* pItem = mrMedium.GetItemSet().GetItem(SID_PROGRESS_STATUSBAR_CONTROL);
if (pItem)
{
pItem->GetValue() >>= mxStatusIndicator;
}
if(mxStatusIndicator.is())
{
sal_Int32 nProgressRange(1000000);
OUString aMsg(SvxResId(RID_SVXSTR_DOC_LOAD));
mxStatusIndicator->start(aMsg, nProgressRange);
// set ProgressRange
uno::Any aProgRange;
aProgRange <<= nProgressRange;
xInfoSet->setPropertyValue( u"ProgressRange"_ustr , aProgRange);
// set ProgressCurrent
uno::Any aProgCurrent;
aProgCurrent <<= sal_Int32(0);
xInfoSet->setPropertyValue( u"ProgressCurrent"_ustr , aProgCurrent);
}
}
// get the input stream (storage or stream)
uno::Reference < embed::XStorage > xStorage = mrMedium.GetStorage();
xInfoSet->setPropertyValue( u"SourceStorage"_ustr, Any( xStorage ) );
if( !xStorage.is() )
nRet = SD_XML_READERROR;
if( ERRCODE_NONE == nRet )
{
xGraphicHelper = SvXMLGraphicHelper::Create( xStorage,
SvXMLGraphicHelperMode::Read );
xGraphicStorageHandler = xGraphicHelper.get();
xObjectHelper = SvXMLEmbeddedObjectHelper::Create(
xStorage, *pDoc->GetPersist(),
SvXMLEmbeddedObjectHelperMode::Read );
xObjectResolver = xObjectHelper.get();
}
// Set base URI
OUString const baseURI(mrMedium.GetBaseURL());
// needed for relative URLs, but in clipboard copy/paste there may be none
SAL_INFO_IF(baseURI.isEmpty(), "sd.filter", "SdXMLFilter: no base URL");
xInfoSet->setPropertyValue(u"BaseURI"_ustr, Any(baseURI));
if( ERRCODE_NONE == nRet && SfxObjectCreateMode::EMBEDDED == mrDocShell.GetCreateMode() )
{
OUString aName;
const SfxStringItem* pDocHierarchItem =
mrMedium.GetItemSet().GetItem(SID_DOC_HIERARCHICALNAME);
if ( pDocHierarchItem )
aName = pDocHierarchItem->GetValue();
else
aName = "dummyObjectName" ;
if( !aName.isEmpty() )
xInfoSet->setPropertyValue( u"StreamRelPath"_ustr, Any( aName ) );
}
if (SdXMLFilterMode::Organizer == meFilterMode)
xInfoSet->setPropertyValue(u"OrganizerMode"_ustr, uno::Any(true));
if( ERRCODE_NONE == nRet )
{
// prepare filter arguments
Sequence<Any> aFilterArgs( 4 );
Any *pArgs = aFilterArgs.getArray();
*pArgs++ <<= xInfoSet;
*pArgs++ <<= xGraphicStorageHandler;
*pArgs++ <<= xObjectResolver;
*pArgs++ <<= mxStatusIndicator;
Sequence<Any> aEmptyArgs( 2 );
pArgs = aEmptyArgs.getArray();
*pArgs++ <<= xInfoSet;
*pArgs++ <<= mxStatusIndicator;
const OUString aName( mrMedium.GetName() );
XML_SERVICES const * pServices = getServices( true, IsDraw(), mnStoreVer );
ErrCodeMsg nWarn = ERRCODE_NONE;
ErrCodeMsg nWarn2 = ERRCODE_NONE;
// read storage streams
// #i103539#: always read meta.xml for generator
nWarn = ReadThroughComponent(
xStorage, xModelComp, "meta.xml", rxContext,
pServices->mpMeta,
aEmptyArgs, aName, false );
if( meFilterMode != SdXMLFilterMode::Organizer )
{
nWarn2 = ReadThroughComponent(
xStorage, xModelComp, "settings.xml", rxContext,
pServices->mpSettings,
aFilterArgs, aName, false );
}
nRet = ReadThroughComponent(
xStorage, xModelComp, "styles.xml", rxContext,
pServices->mpStyles,
aFilterArgs, aName, true );
if( !nRet && (meFilterMode != SdXMLFilterMode::Organizer) )
nRet = ReadThroughComponent(
xStorage, xModelComp, "content.xml", rxContext,
pServices->mpContent,
aFilterArgs, aName, true );
if( !nRet )
{
if( nWarn )
nRet = std::move(nWarn);
else if( nWarn2 )
nRet = std::move(nWarn2);
}
}
if( xGraphicHelper )
xGraphicHelper->dispose();
xGraphicHelper.clear();
xGraphicStorageHandler = nullptr;
if( xObjectHelper.is() )
xObjectHelper->dispose();
xObjectHelper.clear();
xObjectResolver = nullptr;
if( mxStatusIndicator.is() )
mxStatusIndicator->end();
if( mxModel.is() )
mxModel->unlockControllers();
if( nRet == ERRCODE_NONE )
pDoc->UpdateAllLinks();
if( nRet == ERRCODE_NONE || nRet == SD_XML_READERROR )
;
else if( nRet == ERRCODE_IO_BROKENPACKAGE && xStorage.is() )
nError = ERRCODE_IO_BROKENPACKAGE;
else
{
// TODO/LATER: this is completely wrong! Filter code should never call ErrorHandler directly!
ErrorHandler::HandleError( nRet );
if( nRet.IsWarning() )
nRet = ERRCODE_NONE;
}
// clear unused named items from item pool
::svx::DropUnusedNamedItems(mxModel);
// set BuildId on XModel for later OLE object loading
if( xInfoSet.is() )
{
uno::Reference< beans::XPropertySet > xModelSet( mxModel, uno::UNO_QUERY );
if( xModelSet.is() )
{
uno::Reference< beans::XPropertySetInfo > xModelSetInfo( xModelSet->getPropertySetInfo() );
static constexpr OUString sPropName( u"BuildId"_ustr );
OUString sBuildId;
xInfoSet->getPropertyValue(sPropName) >>= sBuildId;
if( xModelSetInfo.is() && xModelSetInfo->hasPropertyByName(sPropName) )
{
xModelSet->setPropertyValue( sPropName, Any( sBuildId ) );
}
bool bTransform = false;
if( nRet == ERRCODE_NONE )
{
if( !sBuildId.isEmpty() )
{
sal_Int32 nIndex = sBuildId.indexOf('$');
if (sBuildId.indexOf(';') == -1 && nIndex != -1)
{
sal_Int32 nUPD = o3tl::toInt32(sBuildId.subView( 0, nIndex ));
if( nUPD == 300 )
{
sal_Int32 nBuildId = o3tl::toInt32(sBuildId.subView( nIndex+1 ));
if( (nBuildId > 0) && (nBuildId < 9316) )
bTransform = true; // treat OOo 3.0 beta1 as OOo 2.x
}
else if( (nUPD == 680) || ( nUPD >= 640 && nUPD <= 645 ) )
bTransform = true;
}
}
else
{
// check for binary formats
std::shared_ptr<const SfxFilter> pFilter = mrMedium.GetFilter();
if( pFilter )
{
OUString typeName(pFilter->GetRealTypeName());
if( typeName.startsWith( "impress_StarImpress" ) ||
typeName.startsWith( "draw_StarDraw" ) )
{
bTransform = true;
}
}
}
}
if( bTransform )
TransformOOo2xDocument( pDoc );
}
}
fixupOutlinePlaceholderNumberingDepths(pDoc);
pDoc->EnableUndo(bWasUndo);
mrDocShell.ClearUndoBuffer();
return nRet == ERRCODE_NONE;
}
bool IsSlideSorterPaste(::sd::DrawDocShell& rDocSh)
{
uno::Reference<document::XDocumentProperties> xSource = rDocSh.getDocProperties();
uno::Reference<beans::XPropertyContainer> xSourcePropertyContainer = xSource->getUserDefinedProperties();
uno::Reference<beans::XPropertySet> xSourcePropertySet(xSourcePropertyContainer, uno::UNO_QUERY);
if (!xSourcePropertySet)
return false;
const uno::Sequence<beans::Property> lProps = xSourcePropertySet->getPropertySetInfo()->getProperties();
for (const beans::Property& rProp : lProps)
{
if (rProp.Name != "slidesorter")
continue;
uno::Any aFromSlideSorter = xSourcePropertySet->getPropertyValue("slidesorter");
bool bFromSlideSorter(false);
aFromSlideSorter >>= bFromSlideSorter;
return bFromSlideSorter;
}
return false;
}
bool SdXMLFilter::Export()
{
rtl::Reference<SvXMLEmbeddedObjectHelper> xObjectHelper;
rtl::Reference<SvXMLGraphicHelper> xGraphicHelper;
bool bDocRet = false;
if( !mxModel.is() )
{
SAL_WARN( "sd.filter","Got NO Model in XMLExport");
return false;
}
bool bLocked = mxModel->hasControllersLocked();
try
{
mxModel->lockControllers();
uno::Reference< lang::XServiceInfo > xServiceInfo( mxModel, uno::UNO_QUERY );
if( !xServiceInfo.is() || !xServiceInfo->supportsService( u"com.sun.star.drawing.GenericDrawingDocument"_ustr ) )
{
SAL_WARN( "sd.filter", "Model is no DrawingDocument in XMLExport" );
return false;
}
const uno::Reference<uno::XComponentContext>& xContext( ::comphelper::getProcessComponentContext() );
uno::Reference< xml::sax::XWriter > xWriter = xml::sax::Writer::create( xContext );
/** property map for export info set */
static PropertyMapEntry const aExportInfoMap[] =
{
{ u"ProgressRange"_ustr, 0, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
{ u"ProgressMax"_ustr, 0, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
{ u"ProgressCurrent"_ustr, 0, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
{ u"UsePrettyPrinting"_ustr,0, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
{ u"PageLayoutNames"_ustr, 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
{ u"BaseURI"_ustr, 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
{ u"StreamRelPath"_ustr, 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
{ u"StreamName"_ustr, 0, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
{ u"StyleNames"_ustr, 0, cppu::UnoType<Sequence<OUString>>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
{ u"StyleFamilies"_ustr, 0, cppu::UnoType<Sequence<sal_Int32>>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
{ u"TargetStorage"_ustr, 0, cppu::UnoType<embed::XStorage>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
};
uno::Reference< beans::XPropertySet > xInfoSet( GenericPropertySet_CreateInstance( new PropertySetInfo( aExportInfoMap ) ) );
bool bUsePrettyPrinting = officecfg::Office::Common::Save::Document::PrettyPrinting::get();
xInfoSet->setPropertyValue( u"UsePrettyPrinting"_ustr, Any( bUsePrettyPrinting ) );
const uno::Reference < embed::XStorage > xStorage = mrMedium.GetOutputStorage();
// Set base URI
OUString sPropName( u"BaseURI"_ustr );
xInfoSet->setPropertyValue( sPropName, Any( mrMedium.GetBaseURL( true ) ) );
xInfoSet->setPropertyValue( u"TargetStorage"_ustr, Any( xStorage ) );
if( SfxObjectCreateMode::EMBEDDED == mrDocShell.GetCreateMode() )
{
OUString aName;
const SfxStringItem* pDocHierarchItem =
mrMedium.GetItemSet().GetItem(SID_DOC_HIERARCHICALNAME);
if ( pDocHierarchItem )
aName = pDocHierarchItem->GetValue();
if( !aName.isEmpty() )
{
sPropName = "StreamRelPath";
xInfoSet->setPropertyValue( sPropName, Any( aName ) );
}
}
// initialize descriptor
uno::Sequence< beans::PropertyValue > aDescriptor( 1 );
beans::PropertyValue* pProps = aDescriptor.getArray();
pProps[0].Name = "FileName";
pProps[0].Value <<= mrMedium.GetName();
{
uno::Reference< document::XEmbeddedObjectResolver > xObjectResolver;
uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
// create helper for graphic and ole export if we have a storage
if( xStorage.is() )
{
xObjectHelper = SvXMLEmbeddedObjectHelper::Create( xStorage, *mrDocShell.GetDoc()->GetPersist(), SvXMLEmbeddedObjectHelperMode::Write );
xObjectResolver = xObjectHelper.get();
xGraphicHelper = SvXMLGraphicHelper::Create( xStorage, SvXMLGraphicHelperMode::Write );
xGraphicStorageHandler = xGraphicHelper.get();
}
CreateStatusIndicator();
if(mxStatusIndicator.is())
{
sal_Int32 nProgressRange(1000000);
OUString aMsg(SdResId(STR_SAVE_DOC));
mxStatusIndicator->start(aMsg, nProgressRange);
// set ProgressRange
uno::Any aProgRange;
aProgRange <<= nProgressRange;
xInfoSet->setPropertyValue( u"ProgressRange"_ustr , aProgRange);
// set ProgressCurrent
uno::Any aProgCurrent;
aProgCurrent <<= sal_Int32(0);
xInfoSet->setPropertyValue( u"ProgressCurrent"_ustr , aProgCurrent);
}
XML_SERVICES const * pServiceNames = getServices( false, IsDraw(), mnStoreVer );
XML_SERVICEMAP aServices[5]; sal_uInt16 i = 0;
aServices[i ].mpService = pServiceNames->mpStyles;
aServices[i++].mpStream = "styles.xml";
aServices[i ].mpService = pServiceNames->mpContent;
aServices[i++].mpStream = "content.xml";
aServices[i ].mpService = pServiceNames->mpSettings;
aServices[i++].mpStream = "settings.xml";
bool bExportMeta = mrDocShell.GetCreateMode() != SfxObjectCreateMode::EMBEDDED;
if (!bExportMeta)
{
// Export meta information anyway when this is a copy from the
// slide sorter so we can distinguish that at paste time
bExportMeta = IsSlideSorterPaste(mrDocShell);
}
if (bExportMeta)
{
aServices[i ].mpService = pServiceNames->mpMeta;
aServices[i++].mpStream = "meta.xml";
};
aServices[i].mpService = nullptr;
aServices[i].mpStream = nullptr;
XML_SERVICEMAP* pServices = aServices;
std::unordered_map<OString, OUString> maEmbeddedFontFiles;
// doc export
do
{
SAL_INFO( "sd.filter", "exporting substream " << pServices->mpStream );
uno::Reference<io::XOutputStream> xDocOut;
if( xStorage.is() )
{
const OUString sDocName( OUString::createFromAscii( pServices->mpStream ) );
uno::Reference<io::XStream> xStream =
xStorage->openStreamElement( sDocName,
embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
DBG_ASSERT(xStream.is(), "Can't create output stream in package!");
if( !xStream.is() )
return false;
xDocOut = xStream->getOutputStream();
Reference <beans::XPropertySet > xProps( xStream, uno::UNO_QUERY );
if( !xDocOut.is() || !xProps.is() )
return false;
xProps->setPropertyValue( u"MediaType"_ustr, Any(u"text/xml"_ustr));
// encrypt all streams
xProps->setPropertyValue( u"UseCommonStoragePasswordEncryption"_ustr,
uno::Any( true ) );
xInfoSet->setPropertyValue( u"StreamName"_ustr, Any( sDocName ) );
}
xWriter->setOutputStream( xDocOut );
uno::Sequence< uno::Any > aArgs( 2 + ( mxStatusIndicator.is() ? 1 : 0 ) + ( xGraphicStorageHandler.is() ? 1 : 0 ) + ( xObjectResolver.is() ? 1 : 0 ) );
uno::Any* pArgs = aArgs.getArray();
*pArgs++ <<= xInfoSet;
if (xGraphicStorageHandler.is())
*pArgs++ <<= xGraphicStorageHandler;
if (xObjectResolver.is())
*pArgs++ <<= xObjectResolver;
if (mxStatusIndicator.is())
*pArgs++ <<= mxStatusIndicator;
*pArgs <<= xWriter;
uno::Reference< document::XFilter > xFilter( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii( pServices->mpService ), aArgs, xContext ), uno::UNO_QUERY );
if( xFilter.is() )
{
uno::Reference< document::XExporter > xExporter( xFilter, uno::UNO_QUERY );
if( xExporter.is() )
{
xExporter->setSourceDocument( mxModel );
auto pFilter = dynamic_cast<SvXMLExport*>(xFilter.get());
if (pFilter)
{
pFilter->setEmbeddedFontFiles(maEmbeddedFontFiles);
}
// outputstream will be closed by SAX parser
bDocRet = xFilter->filter( aDescriptor );
if (pFilter)
{
maEmbeddedFontFiles = pFilter->getEmbeddedFontFiles();
}
}
}
pServices++;
}
while( bDocRet && pServices->mpService );
if(mxStatusIndicator.is())
mxStatusIndicator->end();
}
}
catch (const uno::Exception &)
{
TOOLS_WARN_EXCEPTION( "sd.filter", "uno Exception caught while exporting");
bDocRet = false;
}
if ( !bLocked )
mxModel->unlockControllers();
if( xGraphicHelper )
xGraphicHelper->dispose();
xGraphicHelper.clear();
if( xObjectHelper )
xObjectHelper->dispose();
xObjectHelper.clear();
return bDocRet;
}
extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportFODP(SvStream &rStream)
{
SdDLL::Init();
sd::DrawDocShellRef xDocSh(new sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Impress));
xDocSh->DoInitNew();
uno::Reference<frame::XModel> xModel(xDocSh->GetModel());
uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(comphelper::getProcessServiceFactory());
uno::Reference<io::XInputStream> xStream(new ::utl::OSeekableInputStreamWrapper(rStream));
uno::Reference<uno::XInterface> xInterface(xMultiServiceFactory->createInstance(u"com.sun.star.comp.Writer.XmlFilterAdaptor"_ustr), uno::UNO_SET_THROW);
css::uno::Sequence<OUString> aUserData
{
u"com.sun.star.comp.filter.OdfFlatXml"_ustr,
u""_ustr,
u"com.sun.star.comp.Impress.XMLOasisImporter"_ustr,
u"com.sun.star.comp.Impress.XMLOasisExporter"_ustr,
u""_ustr,
u""_ustr,
u"true"_ustr
};
uno::Sequence<beans::PropertyValue> aAdaptorArgs(comphelper::InitPropertySequence(
{
{ "UserData", uno::Any(aUserData) },
}));
css::uno::Sequence<uno::Any> aOuterArgs{ uno::Any(aAdaptorArgs) };
uno::Reference<lang::XInitialization> xInit(xInterface, uno::UNO_QUERY_THROW);
xInit->initialize(aOuterArgs);
uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY_THROW);
uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
{
{ "InputStream", uno::Any(xStream) },
{ "URL", uno::Any(u"private:stream"_ustr) },
}));
xImporter->setTargetDocument(xModel);
uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY_THROW);
//SetLoading hack because the document properties will be re-initted
//by the xml filter and during the init, while it's considered uninitialized,
//setting a property will inform the document it's modified, which attempts
//to update the properties, which throws cause the properties are uninitialized
xDocSh->SetLoading(SfxLoadedFlags::NONE);
bool ret = xFilter->filter(aArgs);
xDocSh->SetLoading(SfxLoadedFlags::ALL);
xDocSh->DoClose();
return ret;
}
extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportPPTX(SvStream &rStream)
{
SdDLL::Init();
sd::DrawDocShellRef xDocSh(new sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Impress));
xDocSh->DoInitNew();
uno::Reference<frame::XModel> xModel(xDocSh->GetModel());
uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(comphelper::getProcessServiceFactory());
uno::Reference<io::XInputStream> xStream(new utl::OSeekableInputStreamWrapper(rStream));
uno::Reference<document::XFilter> xFilter(xMultiServiceFactory->createInstance(u"com.sun.star.comp.oox.ppt.PowerPointImport"_ustr), uno::UNO_QUERY_THROW);
uno::Reference<document::XImporter> xImporter(xFilter, uno::UNO_QUERY_THROW);
uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
{
{ "InputStream", uno::Any(xStream) },
{ "InputMode", uno::Any(true) },
}));
xImporter->setTargetDocument(xModel);
//SetLoading hack because the document properties will be re-initted
//by the xml filter and during the init, while it's considered uninitialized,
//setting a property will inform the document it's modified, which attempts
//to update the properties, which throws cause the properties are uninitialized
xDocSh->SetLoading(SfxLoadedFlags::NONE);
bool ret = false;
try
{
ret = xFilter->filter(aArgs);
}
catch (...)
{
}
xDocSh->SetLoading(SfxLoadedFlags::ALL);
xDocSh->DoClose();
return ret;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1001 The 'aFromSlideSorter' variable is assigned but is not used by the end of the function.