xref: /core/sc/source/filter/xml/xmlwrap.cxx (revision 889dc7bf)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <vcl/errinf.hxx>
21 #include <sfx2/docfile.hxx>
22 #include <sfx2/objsh.hxx>
23 #include <sot/storage.hxx>
24 #include <osl/diagnose.h>
25 #include <comphelper/fileformat.h>
26 #include <comphelper/processfactory.hxx>
27 #include <comphelper/propertysequence.hxx>
28 #include <svx/dialmgr.hxx>
29 #include <svx/strings.hrc>
30 #include <svx/xmlgrhlp.hxx>
31 #include <svtools/sfxecode.hxx>
32 #include <sfx2/frame.hxx>
33 #include <svl/itemset.hxx>
34 #include <svl/stritem.hxx>
35 #include <sfx2/sfxsids.hrc>
36 #include <com/sun/star/container/XChild.hpp>
37 #include <com/sun/star/beans/XPropertySetInfo.hpp>
38 #include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp>
39 #include <com/sun/star/xml/sax/InputSource.hpp>
40 #include <com/sun/star/xml/sax/Parser.hpp>
41 #include <com/sun/star/xml/sax/XFastParser.hpp>
42 #include <com/sun/star/xml/sax/Writer.hpp>
43 #include <com/sun/star/xml/sax/SAXParseException.hpp>
44 #include <com/sun/star/frame/XModel.hpp>
45 #include <com/sun/star/beans/PropertyAttribute.hpp>
46 #include <comphelper/propertysetinfo.hxx>
47 #include <comphelper/genericpropertyset.hxx>
48 #include <com/sun/star/packages/WrongPasswordException.hpp>
49 #include <com/sun/star/packages/zip/ZipIOException.hpp>
50 #include <com/sun/star/embed/ElementModes.hpp>
51 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
52 #include <com/sun/star/rdf/XDocumentMetadataAccess.hpp>
53 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
54 #include <com/sun/star/task/XStatusIndicator.hpp>
55 
56 #include <sfx2/DocumentMetadataAccess.hxx>
57 #include <comphelper/documentconstants.hxx>
58 #include <svx/xmleohlp.hxx>
59 #include <sal/log.hxx>
60 #include <unotools/saveopt.hxx>
61 #include <tools/diagnose_ex.h>
62 
63 #include <document.hxx>
64 #include <xmlwrap.hxx>
65 #include "xmlimprt.hxx"
66 #include "xmlexprt.hxx"
67 #include <globstr.hrc>
68 #include <scresid.hxx>
69 #include <scerrors.hxx>
70 #include "XMLExportSharedData.hxx"
71 #include <docuno.hxx>
72 #include <drwlayer.hxx>
73 #include <sheetdata.hxx>
74 #include "XMLCodeNameProvider.hxx"
75 #include <docsh.hxx>
76 #include <unonames.hxx>
77 
78 using namespace com::sun::star;
79 using namespace css::uno;
80 
81 ScXMLImportWrapper::ScXMLImportWrapper( ScDocShell& rDocSh, SfxMedium* pM, const uno::Reference < embed::XStorage >& xStor ) :
82     mrDocShell(rDocSh),
83     rDoc(rDocSh.GetDocument()),
84     pMedium(pM),
85     xStorage(xStor)
86 {
87     OSL_ENSURE( pMedium || xStorage.is(), "ScXMLImportWrapper: Medium or Storage must be set" );
88 }
89 
90 uno::Reference <task::XStatusIndicator> ScXMLImportWrapper::GetStatusIndicator()
91 {
92     uno::Reference<task::XStatusIndicator> xStatusIndicator;
93     if (pMedium)
94     {
95         SfxItemSet* pSet = pMedium->GetItemSet();
96         if (pSet)
97         {
98             const SfxUnoAnyItem* pItem = pSet->GetItem<SfxUnoAnyItem>(SID_PROGRESS_STATUSBAR_CONTROL);
99             if (pItem)
100                 xStatusIndicator.set(pItem->GetValue(), uno::UNO_QUERY);
101         }
102     }
103     return xStatusIndicator;
104 }
105 
106 ErrCode ScXMLImportWrapper::ImportFromComponent(const uno::Reference<uno::XComponentContext>& xContext,
107     const uno::Reference<frame::XModel>& xModel, const uno::Reference<xml::sax::XParser>& xParser,
108     xml::sax::InputSource& aParserInput,
109     const OUString& sComponentName, const OUString& sDocName,
110     const OUString& sOldDocName, const uno::Sequence<uno::Any>& aArgs,
111     bool bMustBeSuccessfull)
112 {
113     uno::Reference < io::XStream > xDocStream;
114     if ( !xStorage.is() && pMedium )
115         xStorage = pMedium->GetStorage();
116 
117     bool bEncrypted = false;
118     OUString sStream(sDocName);
119     if( xStorage.is() )
120     {
121         try
122         {
123             if ( xStorage->hasByName(sDocName) && xStorage->isStreamElement( sDocName) )
124                 xDocStream = xStorage->openStreamElement( sDocName, embed::ElementModes::READ );
125             else if (!sOldDocName.isEmpty() && xStorage->hasByName(sOldDocName) && xStorage->isStreamElement( sOldDocName) )
126             {
127                 xDocStream = xStorage->openStreamElement( sOldDocName, embed::ElementModes::READ );
128                 sStream = sOldDocName;
129             }
130             else
131                 return ERRCODE_NONE;
132 
133             aParserInput.aInputStream = xDocStream->getInputStream();
134             uno::Reference < beans::XPropertySet > xSet( xDocStream, uno::UNO_QUERY );
135 
136             uno::Any aAny = xSet->getPropertyValue("Encrypted");
137             aAny >>= bEncrypted;
138         }
139         catch( const packages::WrongPasswordException& )
140         {
141             return ERRCODE_SFX_WRONGPASSWORD;
142         }
143         catch( const packages::zip::ZipIOException& )
144         {
145             return ERRCODE_IO_BROKENPACKAGE;
146         }
147         catch( const uno::Exception& )
148         {
149             return SCERR_IMPORT_UNKNOWN;
150         }
151     }
152     else
153         return SCERR_IMPORT_UNKNOWN;
154 
155     // set Base URL
156     uno::Reference< beans::XPropertySet > xInfoSet;
157     if( aArgs.hasElements() )
158         aArgs.getConstArray()[0] >>= xInfoSet;
159     OSL_ENSURE( xInfoSet.is(), "missing property set" );
160     if( xInfoSet.is() )
161     {
162         xInfoSet->setPropertyValue( "StreamName", uno::makeAny( sStream ) );
163     }
164 
165     ErrCode nReturn = ERRCODE_NONE;
166     rDoc.SetRangeOverflowType(ERRCODE_NONE);   // is modified by the importer if limits are exceeded
167 
168     uno::Reference<xml::sax::XDocumentHandler> xDocHandler(
169         xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
170             sComponentName, aArgs, xContext ),
171         uno::UNO_QUERY );
172     OSL_ENSURE( xDocHandler.is(), "can't get Calc importer" );
173     uno::Reference<document::XImporter> xImporter( xDocHandler, uno::UNO_QUERY );
174     if (xImporter.is())
175         xImporter->setTargetDocument( xModel );
176 
177     ScXMLImport* pImporterImpl = dynamic_cast<ScXMLImport*>(xImporter.get());
178     if (pImporterImpl)
179         pImporterImpl->SetPostProcessData(&maPostProcessData);
180 
181     // connect parser and filter
182     uno::Reference< xml::sax::XFastParser > xFastParser = dynamic_cast<
183                             xml::sax::XFastParser* >( xDocHandler.get() );
184     xParser->setDocumentHandler( xDocHandler );
185 
186     try
187     {
188         if( xFastParser.is() )
189             xFastParser->parseStream( aParserInput );
190         else
191             xParser->parseStream( aParserInput );
192     }
193     catch( const xml::sax::SAXParseException& r )
194     {
195         css::uno::Any ex( cppu::getCaughtException() );
196         // sax parser sends wrapped exceptions,
197         // try to find the original one
198         xml::sax::SAXException aSaxEx = *static_cast<xml::sax::SAXException const *>(&r);
199         bool bTryChild = true;
200 
201         while( bTryChild )
202         {
203             xml::sax::SAXException aTmp;
204             if ( aSaxEx.WrappedException >>= aTmp )
205                 aSaxEx = aTmp;
206             else
207                 bTryChild = false;
208         }
209 
210         packages::zip::ZipIOException aBrokenPackage;
211         if ( aSaxEx.WrappedException >>= aBrokenPackage )
212             return ERRCODE_IO_BROKENPACKAGE;
213         else if( bEncrypted )
214             nReturn = ERRCODE_SFX_WRONGPASSWORD;
215         else
216         {
217             SAL_WARN("sc.filter", "SAX parse exception caught while importing: " << exceptionToString(ex));
218 
219             OUString sErr = OUString::number( r.LineNumber ) +
220                           "," +
221                           OUString::number( r.ColumnNumber );
222 
223             if( !sDocName.isEmpty() )
224             {
225                 nReturn = *new TwoStringErrorInfo(
226                                 (bMustBeSuccessfull ? SCERR_IMPORT_FILE_ROWCOL
227                                                         : SCWARN_IMPORT_FILE_ROWCOL),
228                                 sDocName, sErr,
229                                 DialogMask::ButtonsOk | DialogMask::MessageError );
230             }
231             else
232             {
233                 OSL_ENSURE( bMustBeSuccessfull, "Warnings are not supported" );
234                 nReturn = *new StringErrorInfo( SCERR_IMPORT_FORMAT_ROWCOL, sErr,
235                                  DialogMask::ButtonsOk | DialogMask::MessageError );
236             }
237         }
238     }
239     catch( const xml::sax::SAXException& r )
240     {
241         css::uno::Any ex( cppu::getCaughtException() );
242         packages::zip::ZipIOException aBrokenPackage;
243         if ( r.WrappedException >>= aBrokenPackage )
244             return ERRCODE_IO_BROKENPACKAGE;
245         else if( bEncrypted )
246             nReturn = ERRCODE_SFX_WRONGPASSWORD;
247         else
248         {
249             SAL_WARN("sc.filter", "SAX exception caught while importing: " << exceptionToString(ex));
250 
251             nReturn = SCERR_IMPORT_FORMAT;
252         }
253     }
254     catch( const packages::zip::ZipIOException& )
255     {
256         TOOLS_WARN_EXCEPTION("sc.filter", "Zip exception caught while importing");
257 
258         nReturn = ERRCODE_IO_BROKENPACKAGE;
259     }
260     catch( const io::IOException& )
261     {
262         TOOLS_WARN_EXCEPTION("sc.filter", "IO exception caught while importing");
263 
264         nReturn = SCERR_IMPORT_OPEN;
265     }
266     catch( const uno::Exception& )
267     {
268         TOOLS_WARN_EXCEPTION("sc.filter", "uno exception caught while importing");
269 
270         nReturn = SCERR_IMPORT_UNKNOWN;
271     }
272 
273     // #i31130# Can't use getImplementation here to get the ScXMLImport from xDocHandler,
274     // because when OOo 1.x files are loaded, xDocHandler is the OOo2OasisTransformer.
275     // So the overflow warning ErrorCode is now stored in the document.
276     // Export works differently, there getImplementation still works.
277 
278     if (rDoc.HasRangeOverflow() && !nReturn)
279         nReturn = rDoc.GetRangeOverflowType();
280 
281     // free the component
282     xParser->setDocumentHandler( nullptr );
283 
284     // success!
285     return nReturn;
286 }
287 
288 bool ScXMLImportWrapper::Import( ImportFlags nMode, ErrCode& rError )
289 {
290     uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
291 
292     xml::sax::InputSource aParserInput;
293     if (pMedium)
294         aParserInput.sSystemId = pMedium->GetName();
295 
296     if ( !xStorage.is() && pMedium )
297         xStorage = pMedium->GetStorage();
298 
299     // get parser
300     uno::Reference<xml::sax::XParser> xXMLParser = xml::sax::Parser::create(xContext);
301 
302     // get filter
303     uno::Reference<frame::XModel> xModel = mrDocShell.GetModel();
304 
305     /** property map for export info set */
306     comphelper::PropertyMapEntry const aImportInfoMap[] =
307     {
308         { OUString("ProgressRange"), 0, ::cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
309         { OUString("ProgressMax"), 0, ::cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
310         { OUString("ProgressCurrent"), 0, ::cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
311         { OUString("NumberStyles"), 0, cppu::UnoType<container::XNameAccess>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
312         { OUString("PrivateData"), 0, cppu::UnoType<uno::XInterface>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
313         { OUString("BaseURI"), 0, ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
314         { OUString("StreamRelPath"), 0, ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
315         { OUString("StreamName"), 0, ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
316         { OUString("BuildId"), 0, ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
317         { OUString("VBACompatibilityMode"), 0, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
318         { OUString("ScriptConfiguration"), 0, cppu::UnoType<container::XNameAccess>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
319         { OUString("OrganizerMode"), 0, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
320         { OUString("SourceStorage"), 0, cppu::UnoType<embed::XStorage>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
321         { OUString(SC_UNO_ODS_LOCK_SOLAR_MUTEX), 0, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
322         { OUString(SC_UNO_ODS_IMPORT_STYLES), 0, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
323         { OUString(), 0, css::uno::Type(), 0, 0 }
324     };
325     uno::Reference< beans::XPropertySet > xInfoSet( comphelper::GenericPropertySet_CreateInstance( new comphelper::PropertySetInfo( aImportInfoMap ) ) );
326 
327     // No need to lock solar mutex when calling from the wrapper.
328     xInfoSet->setPropertyValue(SC_UNO_ODS_LOCK_SOLAR_MUTEX, uno::makeAny(false));
329 
330     // ---- get BuildId from parent container if available
331 
332     uno::Reference< container::XChild > xChild( xModel, uno::UNO_QUERY );
333     if( xChild.is() )
334     {
335         uno::Reference< beans::XPropertySet > xParentSet( xChild->getParent(), uno::UNO_QUERY );
336         if( xParentSet.is() )
337         {
338             uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xParentSet->getPropertySetInfo() );
339             OUString sPropName("BuildId" );
340             if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(sPropName) )
341             {
342                 xInfoSet->setPropertyValue( sPropName, xParentSet->getPropertyValue(sPropName) );
343             }
344         }
345     }
346 
347     uno::Reference<task::XStatusIndicator> xStatusIndicator = GetStatusIndicator();
348     if (xStatusIndicator.is())
349     {
350         sal_Int32 nProgressRange(1000000);
351         xStatusIndicator->start(SvxResId(RID_SVXSTR_DOC_LOAD), nProgressRange);
352         xInfoSet->setPropertyValue("ProgressRange", uno::makeAny(nProgressRange));
353     }
354 
355     // Set base URI
356     OSL_ENSURE( pMedium, "There is no medium to get MediaDescriptor from!" );
357     OUString aBaseURL = pMedium ? pMedium->GetBaseURL() : OUString();
358     // needed for relative URLs, but in clipboard copy/paste there may be none
359     SAL_INFO_IF(aBaseURL.isEmpty(), "sc.filter", "ScXMLImportWrapper: no base URL");
360     OUString sPropName("BaseURI");
361     xInfoSet->setPropertyValue( sPropName, uno::makeAny( aBaseURL ) );
362 
363     // TODO/LATER: do not do it for embedded links
364     OUString aName;
365     if (SfxObjectCreateMode::EMBEDDED == mrDocShell.GetCreateMode())
366     {
367         if ( pMedium && pMedium->GetItemSet() )
368         {
369             const SfxStringItem* pDocHierarchItem = static_cast<const SfxStringItem*>(
370                 pMedium->GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME) );
371             if ( pDocHierarchItem )
372                 aName = pDocHierarchItem->GetValue();
373         }
374         else
375             aName = "dummyObjectName";
376 
377         if( !aName.isEmpty() )
378         {
379             sPropName = "StreamRelPath";
380             xInfoSet->setPropertyValue( sPropName, uno::makeAny( aName ) );
381         }
382     }
383 
384     if (mrDocShell.GetCreateMode() == SfxObjectCreateMode::ORGANIZER)
385         xInfoSet->setPropertyValue("OrganizerMode", uno::makeAny(true));
386 
387     xInfoSet->setPropertyValue( "SourceStorage", uno::Any( xStorage ) );
388 
389     bool bOasis = ( SotStorage::GetVersion( xStorage ) > SOFFICE_FILEFORMAT_60 );
390 
391     if ((nMode & ImportFlags::Metadata) && bOasis)
392     {
393         // RDF metadata: ODF >= 1.2
394         try
395         {
396             const uno::Reference< rdf::XDocumentMetadataAccess > xDMA(
397                 xModel, uno::UNO_QUERY_THROW );
398             const uno::Reference< rdf::XURI > xBaseURI(
399                 ::sfx2::createBaseURI( xContext, xModel, aBaseURL, aName ) );
400             uno::Reference<task::XInteractionHandler> xHandler =
401                 mrDocShell.GetMedium()->GetInteractionHandler();
402             xDMA->loadMetadataFromStorage( xStorage, xBaseURI, xHandler );
403         }
404         catch ( const lang::WrappedTargetException & e)
405         {
406             ucb::InteractiveAugmentedIOException iaioe;
407             if ( e.TargetException >>= iaioe )
408             {
409                 rError = SCERR_IMPORT_UNKNOWN;
410             }
411             else
412             {
413                 rError = SCWARN_IMPORT_FEATURES_LOST;
414             }
415         }
416         catch ( const uno::Exception &)
417         {
418             rError = SCWARN_IMPORT_FEATURES_LOST;
419         }
420     }
421 
422     // #i103539#: always read meta.xml for generator
423     ErrCode nMetaRetval(ERRCODE_NONE);
424     if (nMode & ImportFlags::Metadata)
425     {
426         uno::Sequence<uno::Any> aMetaArgs(1);
427         uno::Any* pMetaArgs = aMetaArgs.getArray();
428         pMetaArgs[0] <<= xInfoSet;
429 
430         SAL_INFO( "sc.filter", "meta import start" );
431 
432         nMetaRetval = ImportFromComponent(
433                                 xContext, xModel, xXMLParser, aParserInput,
434                                 bOasis ? OUString("com.sun.star.comp.Calc.XMLOasisMetaImporter")
435                                 : OUString("com.sun.star.comp.Calc.XMLMetaImporter"),
436                                 "meta.xml", "Meta.xml", aMetaArgs, false);
437 
438         SAL_INFO( "sc.filter", "meta import end" );
439     }
440 
441     rtl::Reference<SvXMLGraphicHelper> xGraphicHelper;
442     uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
443 
444     uno::Reference< document::XEmbeddedObjectResolver > xObjectResolver;
445     rtl::Reference<SvXMLEmbeddedObjectHelper> xObjectHelper;
446 
447     if( xStorage.is() )
448     {
449         xGraphicHelper = SvXMLGraphicHelper::Create( xStorage, SvXMLGraphicHelperMode::Read );
450         xGraphicStorageHandler = xGraphicHelper.get();
451 
452         xObjectHelper = SvXMLEmbeddedObjectHelper::Create(xStorage, mrDocShell, SvXMLEmbeddedObjectHelperMode::Read);
453         xObjectResolver = xObjectHelper.get();
454     }
455     uno::Sequence<uno::Any> aStylesArgs(4);
456     uno::Any* pStylesArgs = aStylesArgs.getArray();
457     pStylesArgs[0] <<= xInfoSet;
458     pStylesArgs[1] <<= xGraphicStorageHandler;
459     pStylesArgs[2] <<= xStatusIndicator;
460     pStylesArgs[3] <<= xObjectResolver;
461 
462     ErrCode nSettingsRetval(ERRCODE_NONE);
463     if (nMode & ImportFlags::Settings)
464     {
465         //  Settings must be loaded first because of the printer setting,
466         //  which is needed in the page styles (paper tray).
467 
468         uno::Sequence<uno::Any> aSettingsArgs(1);
469         uno::Any* pSettingsArgs = aSettingsArgs.getArray();
470         pSettingsArgs[0] <<= xInfoSet;
471 
472         SAL_INFO( "sc.filter", "settings import start" );
473 
474         nSettingsRetval = ImportFromComponent(
475                             xContext, xModel, xXMLParser, aParserInput,
476                             bOasis ? OUString("com.sun.star.comp.Calc.XMLOasisSettingsImporter")
477                                    : OUString("com.sun.star.comp.Calc.XMLSettingsImporter"),
478                             "settings.xml", "", aSettingsArgs, false);
479 
480         SAL_INFO( "sc.filter", "settings import end" );
481     }
482 
483     ErrCode nStylesRetval(ERRCODE_NONE);
484     if (nMode & ImportFlags::Styles)
485     {
486         SAL_INFO( "sc.filter", "styles import start" );
487 
488         nStylesRetval = ImportFromComponent(xContext, xModel, xXMLParser, aParserInput,
489             bOasis ? OUString("com.sun.star.comp.Calc.XMLOasisStylesImporter")
490                    : OUString("com.sun.star.comp.Calc.XMLStylesImporter"),
491             "styles.xml",
492             "", aStylesArgs, true);
493 
494         SAL_INFO( "sc.filter", "styles import end" );
495     }
496 
497     ErrCode nDocRetval(ERRCODE_NONE);
498     if (nMode & ImportFlags::Content)
499     {
500         if (mrDocShell.GetCreateMode() == SfxObjectCreateMode::INTERNAL)
501             // We only need to import content for external link cache document.
502             xInfoSet->setPropertyValue(SC_UNO_ODS_IMPORT_STYLES, uno::makeAny(false));
503 
504         uno::Sequence<uno::Any> aDocArgs(4);
505         uno::Any* pDocArgs = aDocArgs.getArray();
506         pDocArgs[0] <<= xInfoSet;
507         pDocArgs[1] <<= xGraphicStorageHandler;
508         pDocArgs[2] <<= xStatusIndicator;
509         pDocArgs[3] <<= xObjectResolver;
510 
511         SAL_INFO( "sc.filter", "content import start" );
512 
513         nDocRetval = ImportFromComponent(xContext, xModel, xXMLParser, aParserInput,
514             bOasis ? OUString("com.sun.star.comp.Calc.XMLOasisContentImporter")
515                    : OUString("com.sun.star.comp.Calc.XMLContentImporter"),
516             "content.xml",
517             "Content.xml", aDocArgs,
518             true);
519 
520         SAL_INFO( "sc.filter", "content import end" );
521     }
522     if( xGraphicHelper.is() )
523         xGraphicHelper->dispose();
524     xGraphicHelper.clear();
525 
526     if( xObjectHelper.is() )
527         xObjectHelper->dispose();
528     xObjectHelper.clear();
529 
530     if (xStatusIndicator.is())
531         xStatusIndicator->end();
532 
533     bool bRet = false;
534     if (nDocRetval)
535     {
536         rError = nDocRetval;
537         if (nDocRetval == SCWARN_IMPORT_RANGE_OVERFLOW ||
538             nDocRetval == SCWARN_IMPORT_ROW_OVERFLOW ||
539             nDocRetval == SCWARN_IMPORT_COLUMN_OVERFLOW ||
540             nDocRetval == SCWARN_IMPORT_SHEET_OVERFLOW)
541             bRet = true;
542     }
543     else if (nStylesRetval)
544         rError = nStylesRetval;
545     else if (nMetaRetval)
546         rError = nMetaRetval;
547     else if (nSettingsRetval)
548         rError = nSettingsRetval;
549     else
550         bRet = true;
551 
552     // set BuildId on XModel for later OLE object loading
553     if( xInfoSet.is() )
554     {
555         uno::Reference< beans::XPropertySet > xModelSet( xModel, uno::UNO_QUERY );
556         if( xModelSet.is() )
557         {
558             uno::Reference< beans::XPropertySetInfo > xModelSetInfo( xModelSet->getPropertySetInfo() );
559             OUString sBuildPropName("BuildId" );
560             if( xModelSetInfo.is() && xModelSetInfo->hasPropertyByName(sBuildPropName) )
561             {
562                 xModelSet->setPropertyValue( sBuildPropName, xInfoSet->getPropertyValue(sBuildPropName) );
563             }
564         }
565 
566         // Set Code Names
567         uno::Any aAny = xInfoSet->getPropertyValue("ScriptConfiguration");
568         uno::Reference <container::XNameAccess> xCodeNameAccess;
569         if( aAny >>= xCodeNameAccess )
570             XMLCodeNameProvider::set( xCodeNameAccess, &rDoc );
571 
572         // VBA compatibility
573         bool bVBACompat = false;
574         if ( (xInfoSet->getPropertyValue("VBACompatibilityMode") >>= bVBACompat) && bVBACompat )
575         {
576             /*  Set library container to VBA compatibility mode, this
577                 forces loading the Basic project, which in turn creates the
578                 VBA Globals object and does all related initialization. */
579             if ( xModelSet.is() ) try
580             {
581                 uno::Reference< script::vba::XVBACompatibility > xVBACompat( xModelSet->getPropertyValue(
582                     "BasicLibraries" ), uno::UNO_QUERY_THROW );
583                 xVBACompat->setVBACompatibilityMode( true );
584             }
585             catch( const uno::Exception& )
586             {
587             }
588         }
589     }
590 
591     // Don't test bStylesRetval and bMetaRetval, because it could be an older file which not contain such streams
592     return bRet;//!bStylesOnly ? bDocRetval : bStylesRetval;
593 }
594 
595 static bool lcl_HasValidStream(const ScDocument& rDoc)
596 {
597     SfxObjectShell* pObjSh = rDoc.GetDocumentShell();
598     if ( pObjSh->IsDocShared() )
599         return false;                       // never copy stream from shared file
600 
601     // don't read remote file again
602     // (could instead re-use medium directly in that case)
603     SfxMedium* pSrcMed = rDoc.GetDocumentShell()->GetMedium();
604     if ( !pSrcMed || pSrcMed->IsRemote() )
605         return false;
606 
607     SCTAB nTabCount = rDoc.GetTableCount();
608     for (SCTAB nTab=0; nTab<nTabCount; ++nTab)
609         if (rDoc.IsStreamValid(nTab))
610             return true;
611     return false;
612 }
613 
614 bool ScXMLImportWrapper::ExportToComponent(const uno::Reference<uno::XComponentContext>& xContext,
615     const uno::Reference<frame::XModel>& xModel, const uno::Reference<xml::sax::XWriter>& xWriter,
616     const uno::Sequence<beans::PropertyValue>& aDescriptor, const OUString& sName,
617     const OUString& sMediaType, const OUString& sComponentName,
618     const uno::Sequence<uno::Any>& aArgs, std::unique_ptr<ScMySharedData>& pSharedData)
619 {
620     bool bRet(false);
621     uno::Reference<io::XOutputStream> xOut;
622     uno::Reference<io::XStream> xStream;
623 
624     if ( !xStorage.is() && pMedium )
625         xStorage = pMedium->GetOutputStorage();
626 
627     if( xStorage.is() )
628     {
629         // #96807#; trunc stream before use, because it could be an existing stream
630         // and the new content could be shorter than the old content. In this case
631         // would not all be over written by the new content and the xml file
632         // would not be valid.
633         xStream = xStorage->openStreamElement( sName, embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
634         uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
635         if (xSet.is())
636         {
637             xSet->setPropertyValue("MediaType", uno::makeAny(sMediaType));
638 
639             // advise storage impl to use common encryption
640             xSet->setPropertyValue( "UseCommonStoragePasswordEncryption", uno::makeAny(true) );
641         }
642 
643         xOut = xStream->getOutputStream();
644     }
645 
646     // set Base URL
647     uno::Reference< beans::XPropertySet > xInfoSet;
648     if( aArgs.hasElements() )
649         aArgs.getConstArray()[0] >>= xInfoSet;
650     OSL_ENSURE( xInfoSet.is(), "missing property set" );
651     if( xInfoSet.is() )
652     {
653         xInfoSet->setPropertyValue( "StreamName", uno::makeAny( sName ) );
654     }
655 
656     xWriter->setOutputStream( xOut );
657 
658     uno::Reference<document::XFilter> xFilter(
659         xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
660             sComponentName , aArgs, xContext ),
661         uno::UNO_QUERY );
662     OSL_ENSURE( xFilter.is(), "can't get exporter" );
663     uno::Reference<document::XExporter> xExporter( xFilter, uno::UNO_QUERY );
664     if (xExporter.is())
665         xExporter->setSourceDocument( xModel );
666 
667     if ( xFilter.is() )
668     {
669         ScXMLExport* pExport = static_cast<ScXMLExport*>(comphelper::getUnoTunnelImplementation<SvXMLExport>(xFilter));
670         pExport->SetSharedData(std::move(pSharedData));
671 
672         // if there are sheets to copy, get the source stream
673         if ( sName == "content.xml" && lcl_HasValidStream(rDoc) && ( pExport->getExportFlags() & SvXMLExportFlags::OASIS ) )
674         {
675             // old stream is still in this file's storage - open read-only
676 
677             // #i106854# use the document's storage directly, without a temporary SfxMedium
678             uno::Reference<embed::XStorage> xTmpStorage = rDoc.GetDocumentShell()->GetStorage();
679             uno::Reference<io::XStream> xSrcStream;
680             uno::Reference<io::XInputStream> xSrcInput;
681 
682             // #i108978# If an embedded object is saved and no events are notified, don't use the stream
683             // because without the ...DONE events, stream positions aren't updated.
684             ScSheetSaveData* pSheetData = comphelper::getUnoTunnelImplementation<ScModelObj>(xModel)->GetSheetSaveData();
685             if (pSheetData && pSheetData->IsInSupportedSave())
686             {
687                 try
688                 {
689                     if (xTmpStorage.is())
690                         xSrcStream = xTmpStorage->openStreamElement( sName, embed::ElementModes::READ );
691                     if (xSrcStream.is())
692                         xSrcInput = xSrcStream->getInputStream();
693                 }
694                 catch ( const uno::Exception&)
695                 {
696                     // stream not available (for example, password protected) - save normally (xSrcInput is null)
697                 }
698             }
699 
700             pExport->SetSourceStream( xSrcInput );
701             bRet = xFilter->filter( aDescriptor );
702             pExport->SetSourceStream( uno::Reference<io::XInputStream>() );
703 
704             // If there was an error, reset all stream flags, so the next save attempt will use normal saving.
705             // #i110692# For embedded objects, the stream may be unavailable for one save operation (m_pAntiImpl)
706             // and become available again later. But after saving normally once, the stream positions aren't
707             // valid anymore, so the flags also have to be reset if the stream wasn't available.
708             if ( !bRet || !xSrcInput.is() )
709             {
710                 SCTAB nTabCount = rDoc.GetTableCount();
711                 for (SCTAB nTab=0; nTab<nTabCount; nTab++)
712                     rDoc.SetStreamValid(nTab, false);
713             }
714         }
715         else
716             bRet = xFilter->filter( aDescriptor );
717 
718         pSharedData = pExport->ReleaseSharedData();
719     }
720 
721     return bRet;
722 }
723 
724 bool ScXMLImportWrapper::Export(bool bStylesOnly)
725 {
726     // Prevent all broadcasting and repaints and notification of accessibility
727     // during mass creation of captions, which is a major bottleneck and not
728     // needed during Save.
729     ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
730     bool bOldLock = bool();
731     if (pDrawLayer)
732     {
733         bOldLock = pDrawLayer->isLocked();
734         pDrawLayer->setLock(true);
735     }
736 
737     rDoc.CreateAllNoteCaptions();
738 
739     if (pDrawLayer)
740         pDrawLayer->setLock(bOldLock);
741 
742     uno::Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
743 
744     uno::Reference<xml::sax::XWriter> xWriter = xml::sax::Writer::create(xContext);
745 
746     if ( !xStorage.is() && pMedium )
747         xStorage = pMedium->GetOutputStorage();
748 
749     OUString sFileName;
750     OUString sTextMediaType("text/xml");
751     if (pMedium)
752         sFileName = pMedium->GetName();
753     SfxObjectShell* pObjSh = rDoc.GetDocumentShell();
754     uno::Sequence<beans::PropertyValue> aDescriptor( comphelper::InitPropertySequence({
755             { "FileName", uno::Any(sFileName) }
756         }));
757 
758     /** property map for export info set */
759     comphelper::PropertyMapEntry const aExportInfoMap[] =
760     {
761         { OUString("ProgressRange"), 0, ::cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
762         { OUString("ProgressMax"), 0, ::cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
763         { OUString("ProgressCurrent"), 0, ::cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
764         { OUString("WrittenNumberStyles"), 0, cppu::UnoType<uno::Sequence<sal_Int32>>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
765         { OUString("UsePrettyPrinting"), 0, ::cppu::UnoType<sal_Bool>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
766         { OUString("BaseURI"), 0, ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
767         { OUString("StreamRelPath"), 0, ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
768         { OUString("StreamName"), 0, ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
769         { OUString("StyleNames"), 0, cppu::UnoType<uno::Sequence<OUString>>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
770         { OUString("StyleFamilies"), 0, cppu::UnoType<uno::Sequence<sal_Int32>>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
771         { OUString("TargetStorage"), 0, cppu::UnoType<embed::XStorage>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
772         { OUString(), 0, css::uno::Type(), 0, 0 }
773     };
774     uno::Reference< beans::XPropertySet > xInfoSet( comphelper::GenericPropertySet_CreateInstance( new comphelper::PropertySetInfo( aExportInfoMap ) ) );
775 
776     if ( pObjSh && xStorage.is() )
777     {
778         uno::Reference<frame::XModel> xModel(pObjSh->GetModel());
779         uno::Reference<task::XStatusIndicator> xStatusIndicator(GetStatusIndicator());
780         sal_Int32 nProgressRange(1000000);
781         if(xStatusIndicator.is())
782             xStatusIndicator->start(ScResId(STR_SAVE_DOC), nProgressRange);
783         xInfoSet->setPropertyValue("ProgressRange", uno::makeAny(nProgressRange));
784 
785         SvtSaveOptions aSaveOpt;
786         bool bUsePrettyPrinting(aSaveOpt.IsPrettyPrinting());
787         xInfoSet->setPropertyValue("UsePrettyPrinting", uno::makeAny(bUsePrettyPrinting));
788 
789         const OUString sTargetStorage("TargetStorage");
790         xInfoSet->setPropertyValue( sTargetStorage, uno::Any( xStorage ) );
791 
792         OSL_ENSURE( pMedium, "There is no medium to get MediaDescriptor from!" );
793         OUString aBaseURL = pMedium ? pMedium->GetBaseURL( true ) : OUString();
794         OUString sPropName("BaseURI");
795         xInfoSet->setPropertyValue( sPropName, uno::makeAny( aBaseURL ) );
796 
797         // TODO/LATER: do not do it for embedded links
798         if( SfxObjectCreateMode::EMBEDDED == pObjSh->GetCreateMode() )
799         {
800             OUString aName("dummyObjectName");
801             if ( pMedium && pMedium->GetItemSet() )
802             {
803                 const SfxStringItem* pDocHierarchItem = static_cast<const SfxStringItem*>(
804                     pMedium->GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME) );
805                 if ( pDocHierarchItem )
806                     aName = pDocHierarchItem->GetValue();
807             }
808 
809             if( !aName.isEmpty() )
810             {
811                 sPropName = "StreamRelPath";
812                 xInfoSet->setPropertyValue( sPropName, uno::makeAny( aName ) );
813             }
814         }
815 
816         bool bMetaRet(pObjSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED);
817         bool bStylesRet (false);
818         bool bDocRet(false);
819         bool bSettingsRet(false);
820         std::unique_ptr<ScMySharedData> pSharedData;
821 
822         bool bOasis = ( SotStorage::GetVersion( xStorage ) > SOFFICE_FILEFORMAT_60 );
823 
824         // RDF metadata: ODF >= 1.2
825         if ( !bStylesOnly && bOasis )
826         {
827             const uno::Reference< beans::XPropertySet > xPropSet( xStorage, uno::UNO_QUERY_THROW );
828             try
829             {
830                 OUString aVersion;
831                 if (( xPropSet->getPropertyValue("Version") >>= aVersion )
832                     && aVersion != ODFVER_010_TEXT
833                     && aVersion != ODFVER_011_TEXT )
834                 {
835                     const uno::Reference< rdf::XDocumentMetadataAccess > xDMA(
836                         xModel, uno::UNO_QUERY_THROW );
837                     xDMA->storeMetadataToStorage( xStorage );
838                 }
839             }
840             catch ( const beans::UnknownPropertyException &)
841             {
842             }
843             catch ( const uno::Exception &)
844             {
845             }
846         }
847 
848         // meta export
849         if (!bStylesOnly && !bMetaRet)
850         {
851             uno::Sequence<uno::Any> aMetaArgs(3);
852             uno::Any* pMetaArgs = aMetaArgs.getArray();
853             pMetaArgs[0] <<= xInfoSet;
854             pMetaArgs[1] <<= xWriter;
855             pMetaArgs[2] <<= xStatusIndicator;
856 
857             SAL_INFO( "sc.filter", "meta export start" );
858 
859             bMetaRet = ExportToComponent(xContext, xModel, xWriter, aDescriptor,
860                 "meta.xml",
861                 sTextMediaType,
862                 bOasis ? OUString("com.sun.star.comp.Calc.XMLOasisMetaExporter")
863                        : OUString("com.sun.star.comp.Calc.XMLMetaExporter"),
864                 aMetaArgs, pSharedData);
865 
866             SAL_INFO( "sc.filter", "meta export end" );
867         }
868 
869         uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
870         rtl::Reference<SvXMLGraphicHelper> xGraphicHelper;
871 
872         if( xStorage.is() )
873         {
874             xGraphicHelper = SvXMLGraphicHelper::Create( xStorage, SvXMLGraphicHelperMode::Write );
875             xGraphicStorageHandler = xGraphicHelper.get();
876         }
877 
878         auto xObjectHelper = SvXMLEmbeddedObjectHelper::Create(
879             xStorage, *pObjSh, SvXMLEmbeddedObjectHelperMode::Write);
880         uno::Reference<document::XEmbeddedObjectResolver> xObjectResolver(xObjectHelper.get());
881 
882         // styles export
883 
884         {
885             uno::Sequence<uno::Any> aStylesArgs(5);
886             uno::Any* pStylesArgs = aStylesArgs.getArray();
887             pStylesArgs[0] <<= xInfoSet;
888             pStylesArgs[1] <<= xGraphicStorageHandler;
889             pStylesArgs[2] <<= xStatusIndicator;
890             pStylesArgs[3] <<= xWriter;
891             pStylesArgs[4] <<= xObjectResolver;
892 
893             SAL_INFO( "sc.filter", "styles export start" );
894 
895             bStylesRet = ExportToComponent(xContext, xModel, xWriter, aDescriptor,
896                 "styles.xml",
897                 sTextMediaType,
898                 bOasis ? OUString("com.sun.star.comp.Calc.XMLOasisStylesExporter")
899                        : OUString("com.sun.star.comp.Calc.XMLStylesExporter"),
900                 aStylesArgs, pSharedData);
901 
902             SAL_INFO( "sc.filter", "styles export end" );
903         }
904 
905         // content export
906 
907         if (!bStylesOnly)
908         {
909             uno::Sequence<uno::Any> aDocArgs(5);
910             uno::Any* pDocArgs = aDocArgs.getArray();
911             pDocArgs[0] <<= xInfoSet;
912             pDocArgs[1] <<= xGraphicStorageHandler;
913             pDocArgs[2] <<= xStatusIndicator;
914             pDocArgs[3] <<= xWriter;
915             pDocArgs[4] <<= xObjectResolver;
916 
917             SAL_INFO( "sc.filter", "content export start" );
918 
919             bDocRet = ExportToComponent(xContext, xModel, xWriter, aDescriptor,
920                 "content.xml",
921                 sTextMediaType,
922                 bOasis ? OUString("com.sun.star.comp.Calc.XMLOasisContentExporter")
923                        : OUString("com.sun.star.comp.Calc.XMLContentExporter"),
924                 aDocArgs, pSharedData);
925 
926             SAL_INFO( "sc.filter", "content export end" );
927         }
928 
929         if( xGraphicHelper )
930             xGraphicHelper->dispose();
931         xGraphicHelper.clear();
932 
933         if( xObjectHelper )
934             xObjectHelper->dispose();
935         xObjectHelper.clear();
936 
937         // settings export
938 
939         if (!bStylesOnly)
940         {
941             uno::Sequence<uno::Any> aSettingsArgs(3);
942             uno::Any* pSettingsArgs = aSettingsArgs.getArray();
943             pSettingsArgs[0] <<= xInfoSet;
944             pSettingsArgs[1] <<= xWriter;
945             pSettingsArgs[2] <<= xStatusIndicator;
946 
947             SAL_INFO( "sc.filter", "settings export start" );
948 
949             bSettingsRet = ExportToComponent(xContext, xModel, xWriter, aDescriptor,
950                 "settings.xml",
951                 sTextMediaType,
952                 bOasis ? OUString("com.sun.star.comp.Calc.XMLOasisSettingsExporter")
953                        : OUString("com.sun.star.comp.Calc.XMLSettingsExporter"),
954                 aSettingsArgs, pSharedData);
955 
956             SAL_INFO( "sc.filter", "settings export end" );
957         }
958 
959         pSharedData.reset();
960 
961         if (xStatusIndicator.is())
962             xStatusIndicator->end();
963         return bStylesRet && ((!bStylesOnly && bDocRet && bMetaRet && bSettingsRet) || bStylesOnly);
964     }
965 
966     // later: give string descriptor as parameter for doc type
967 
968     return false;
969 }
970 
971 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
972