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
