1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 #include "swdetect.hxx" 31 32 #include <framework/interaction.hxx> 33 #include <com/sun/star/frame/XFrame.hpp> 34 #include <com/sun/star/frame/XModel.hpp> 35 #include <com/sun/star/lang/XUnoTunnel.hpp> 36 #ifndef _UNOTOOLS_PROCESSFACTORY_HXX 37 #include <comphelper/processfactory.hxx> 38 #endif 39 #include <com/sun/star/container/XNameAccess.hpp> 40 #include <com/sun/star/io/XInputStream.hpp> 41 #include <com/sun/star/task/XInteractionHandler.hpp> 42 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> 43 #include <com/sun/star/ucb/CommandAbortedException.hpp> 44 #include <com/sun/star/ucb/InteractiveAppException.hpp> 45 #include <com/sun/star/ucb/XContent.hpp> 46 #include <com/sun/star/packages/zip/ZipIOException.hpp> 47 #ifndef _TOOLKIT_UNOHLP_HXX 48 #include <toolkit/helper/vclunohelper.hxx> 49 #endif 50 #include <ucbhelper/simpleinteractionrequest.hxx> 51 #include <rtl/ustring.h> 52 #include <rtl/logfile.hxx> 53 #include <svl/itemset.hxx> 54 #include <vcl/window.hxx> 55 #include <svl/eitem.hxx> 56 #include <svl/stritem.hxx> 57 #include <tools/urlobj.hxx> 58 #include <vos/mutex.hxx> 59 #include <svtools/sfxecode.hxx> 60 #include <svtools/ehdl.hxx> 61 #include <sot/storinfo.hxx> 62 #include <vcl/svapp.hxx> 63 #include <sfx2/app.hxx> 64 #include <sfx2/sfxsids.hrc> 65 #include <sfx2/request.hxx> 66 #include <sfx2/docfile.hxx> 67 #include <sfx2/docfilt.hxx> 68 #include <sfx2/fcontnr.hxx> 69 #include <sfx2/brokenpackageint.hxx> 70 #include <svtools/FilterConfigItem.hxx> 71 #include <unotools/moduleoptions.hxx> 72 #include <com/sun/star/util/XArchiver.hpp> 73 #include <comphelper/ihwrapnofilter.hxx> 74 75 #include <swdll.hxx> 76 77 using namespace ::com::sun::star; 78 using namespace ::com::sun::star::uno; 79 using namespace ::com::sun::star::io; 80 using namespace ::com::sun::star::frame; 81 using namespace ::com::sun::star::task; 82 using namespace ::com::sun::star::beans; 83 using namespace ::com::sun::star::lang; 84 using namespace ::com::sun::star::ucb; 85 using ::rtl::OUString; 86 87 SwFilterDetect::SwFilterDetect( const REFERENCE < lang::XMultiServiceFactory >& /*xFactory*/ ) 88 { 89 } 90 91 SwFilterDetect::~SwFilterDetect() 92 { 93 } 94 95 ::rtl::OUString SAL_CALL SwFilterDetect::detect( uno::Sequence< beans::PropertyValue >& lDescriptor ) throw( uno::RuntimeException ) 96 { 97 REFERENCE< XInputStream > xStream; 98 REFERENCE< XContent > xContent; 99 REFERENCE< XInteractionHandler > xInteraction; 100 String aURL; 101 ::rtl::OUString sTemp; 102 String aTypeName; // a name describing the type (from MediaDescriptor, usually from flat detection) 103 String aPreselectedFilterName; // a name describing the filter to use (from MediaDescriptor, usually from UI action) 104 105 ::rtl::OUString aDocumentTitle; // interesting only if set in this method 106 107 // opening as template is done when a parameter tells to do so and a template filter can be detected 108 // (otherwise no valid filter would be found) or if the detected filter is a template filter and 109 // there is no parameter that forbids to open as template 110 sal_Bool bOpenAsTemplate = sal_False; 111 sal_Bool bWasReadOnly = sal_False, bReadOnly = sal_False; 112 113 sal_Bool bRepairPackage = sal_False; 114 sal_Bool bRepairAllowed = sal_False; 115 116 // now some parameters that can already be in the array, but may be overwritten or new inserted here 117 // remember their indices in the case new values must be added to the array 118 sal_Int32 nPropertyCount = lDescriptor.getLength(); 119 sal_Int32 nIndexOfFilterName = -1; 120 sal_Int32 nIndexOfInputStream = -1; 121 sal_Int32 nIndexOfContent = -1; 122 sal_Int32 nIndexOfReadOnlyFlag = -1; 123 sal_Int32 nIndexOfTemplateFlag = -1; 124 sal_Int32 nIndexOfDocumentTitle = -1; 125 sal_Int32 nIndexOfInteractionHandler = -1; 126 127 for( sal_Int32 nProperty=0; nProperty<nPropertyCount; ++nProperty ) 128 { 129 // extract properties 130 if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("URL")) ) 131 { 132 lDescriptor[nProperty].Value >>= sTemp; 133 aURL = sTemp; 134 } 135 else if( !aURL.Len() && lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("FileName")) ) 136 { 137 lDescriptor[nProperty].Value >>= sTemp; 138 aURL = sTemp; 139 } 140 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("TypeName")) ) 141 { 142 lDescriptor[nProperty].Value >>= sTemp; 143 aTypeName = sTemp; 144 } 145 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("FilterName")) ) 146 { 147 lDescriptor[nProperty].Value >>= sTemp; 148 aPreselectedFilterName = sTemp; 149 150 // if the preselected filter name is not correct, it must be erased after detection 151 // remember index of property to get access to it later 152 nIndexOfFilterName = nProperty; 153 } 154 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("InputStream")) ) 155 nIndexOfInputStream = nProperty; 156 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("ReadOnly")) ) 157 nIndexOfReadOnlyFlag = nProperty; 158 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("UCBContent")) ) 159 nIndexOfContent = nProperty; 160 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("AsTemplate")) ) 161 { 162 lDescriptor[nProperty].Value >>= bOpenAsTemplate; 163 nIndexOfTemplateFlag = nProperty; 164 } 165 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("InteractionHandler")) ) 166 { 167 lDescriptor[nProperty].Value >>= xInteraction; 168 nIndexOfInteractionHandler = nProperty; 169 } 170 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("RepairPackage")) ) 171 lDescriptor[nProperty].Value >>= bRepairPackage; 172 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("DocumentTitle")) ) 173 nIndexOfDocumentTitle = nProperty; 174 } 175 176 // can't check the type for external filters, so set the "dont" flag accordingly 177 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 178 //SfxFilterFlags nMust = SFX_FILTER_IMPORT, nDont = SFX_FILTER_NOTINSTALLED; 179 180 SfxApplication* pApp = SFX_APP(); 181 SfxAllItemSet *pSet = new SfxAllItemSet( pApp->GetPool() ); 182 TransformParameters( SID_OPENDOC, lDescriptor, *pSet ); 183 SFX_ITEMSET_ARG( pSet, pItem, SfxBoolItem, SID_DOC_READONLY, sal_False ); 184 185 bWasReadOnly = pItem && pItem->GetValue(); 186 187 const SfxFilter* pFilter = 0; 188 String aPrefix = String::CreateFromAscii( "private:factory/" ); 189 if( aURL.Match( aPrefix ) == aPrefix.Len() ) 190 { 191 if( SvtModuleOptions().IsWriter() ) 192 { 193 String aPattern( aPrefix ); 194 aPattern += String::CreateFromAscii("swriter"); 195 if ( aURL.Match( aPattern ) >= aPattern.Len() ) 196 //pFilter = SfxFilter::GetDefaultFilterFromFactory( aURL ); 197 return aTypeName; 198 } 199 } 200 else 201 { 202 // ctor of SfxMedium uses owner transition of ItemSet 203 SfxMedium aMedium( aURL, bWasReadOnly ? STREAM_STD_READ : STREAM_STD_READWRITE, sal_False, NULL, pSet ); 204 aMedium.UseInteractionHandler( sal_True ); 205 if ( aMedium.GetErrorCode() == ERRCODE_NONE ) 206 { 207 // remember input stream and content and put them into the descriptor later 208 // should be done here since later the medium can switch to a version 209 xStream = aMedium.GetInputStream(); 210 xContent = aMedium.GetContent(); 211 bReadOnly = aMedium.IsReadOnly(); 212 213 sal_Bool bIsStorage = aMedium.IsStorage(); 214 if ( bIsStorage ) 215 { 216 uno::Reference< embed::XStorage > xStorage = aMedium.GetStorage( sal_False ); 217 if ( aMedium.GetLastStorageCreationState() != ERRCODE_NONE ) 218 { 219 // error during storage creation means _here_ that the medium 220 // is broken, but we can not handle it in medium since impossibility 221 // to create a storage does not _always_ means that the medium is broken 222 aMedium.SetError( aMedium.GetLastStorageCreationState(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); 223 if ( xInteraction.is() ) 224 { 225 OUString empty; 226 try 227 { 228 InteractiveAppException xException( empty, 229 REFERENCE< XInterface >(), 230 InteractionClassification_ERROR, 231 aMedium.GetError() ); 232 233 REFERENCE< XInteractionRequest > xRequest( 234 new ucbhelper::SimpleInteractionRequest( makeAny( xException ), 235 ucbhelper::CONTINUATION_APPROVE ) ); 236 xInteraction->handle( xRequest ); 237 } 238 catch ( Exception & ) {}; 239 } 240 } 241 else 242 { 243 DBG_ASSERT( xStorage.is(), "At this point storage must exist!" ); 244 245 try 246 { 247 const SfxFilter* pPreFilter = aPreselectedFilterName.Len() ? 248 SfxFilterMatcher().GetFilter4FilterName( aPreselectedFilterName ) : aTypeName.Len() ? 249 SfxFilterMatcher(String::CreateFromAscii("swriter")).GetFilter4EA( aTypeName ) : 0; 250 if (!pPreFilter) 251 pPreFilter = SfxFilterMatcher(String::CreateFromAscii("sweb")).GetFilter4EA( aTypeName ); 252 String aFilterName; 253 if ( pPreFilter ) 254 { 255 aFilterName = pPreFilter->GetName(); 256 aTypeName = pPreFilter->GetTypeName(); 257 } 258 259 aTypeName = SfxFilter::GetTypeFromStorage( xStorage, pPreFilter ? pPreFilter->IsOwnTemplateFormat() : sal_False, &aFilterName ); 260 } 261 catch( lang::WrappedTargetException& aWrap ) 262 { 263 packages::zip::ZipIOException aZipException; 264 265 // repairing is done only if this type is requested from outside 266 // we don't do any type detection on broken packages (f.e. because it might be impossible), so any requested 267 // type will be accepted if the user allows to repair the file 268 if ( ( aWrap.TargetException >>= aZipException ) && ( aTypeName.Len() || aPreselectedFilterName.Len() ) ) 269 { 270 if ( xInteraction.is() ) 271 { 272 // the package is a broken one 273 aDocumentTitle = aMedium.GetURLObject().getName( 274 INetURLObject::LAST_SEGMENT, 275 true, 276 INetURLObject::DECODE_WITH_CHARSET ); 277 278 if ( !bRepairPackage ) 279 { 280 // ask the user whether he wants to try to repair 281 RequestPackageReparation aRequest( aDocumentTitle ); 282 xInteraction->handle( aRequest.GetRequest() ); 283 bRepairAllowed = aRequest.isApproved(); 284 } 285 286 if ( !bRepairAllowed ) 287 { 288 // repair either not allowed or not successful 289 // repair either not allowed or not successful 290 NotifyBrokenPackage aNotifyRequest( aDocumentTitle ); 291 xInteraction->handle( aNotifyRequest.GetRequest() ); 292 293 rtl::Reference< ::comphelper::OIHWrapNoFilterDialog > xHandler = new ::comphelper::OIHWrapNoFilterDialog( xInteraction ); 294 if ( nIndexOfInteractionHandler != -1 ) 295 lDescriptor[nIndexOfInteractionHandler].Value <<= uno::Reference< XInteractionHandler >( static_cast< task::XInteractionHandler* >( xHandler.get() ) ); 296 297 aMedium.SetError( ERRCODE_ABORT, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); 298 } 299 } 300 else 301 // no interaction, error handling as usual 302 aMedium.SetError( ERRCODE_IO_BROKENPACKAGE, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); 303 304 if ( !bRepairAllowed ) 305 { 306 aTypeName.Erase(); 307 aPreselectedFilterName.Erase(); 308 } 309 } 310 } 311 catch( uno::RuntimeException& ) 312 { 313 throw; 314 } 315 catch( uno::Exception& ) 316 { 317 aTypeName.Erase(); 318 aPreselectedFilterName.Erase(); 319 } 320 } 321 } 322 else 323 { 324 aMedium.GetInStream(); 325 if ( aMedium.GetErrorCode() == ERRCODE_NONE ) 326 { 327 if ( aPreselectedFilterName.Len() ) 328 pFilter = SfxFilter::GetFilterByName( aPreselectedFilterName ); 329 else 330 pFilter = SfxFilterMatcher().GetFilter4EA( aTypeName ); 331 332 sal_Bool bTestWriter = !pFilter || pFilter->GetServiceName().EqualsAscii("com.sun.star.text.TextDocument") || 333 pFilter->GetServiceName().EqualsAscii("com.sun.star.text.WebDocument"); 334 sal_Bool bTestGlobal = !pFilter || pFilter->GetServiceName().EqualsAscii("com.sun.star.text.GlobalDocument"); 335 336 const SfxFilter* pOrigFilter = NULL; 337 if ( !bTestWriter && !bTestGlobal && pFilter ) 338 { 339 // cross filter; now this should be a type detection only, not a filter detection 340 // we can simulate it by preserving the preselected filter if the type matches 341 // example: HTML filter for Calc 342 pOrigFilter = pFilter; 343 pFilter = SfxFilterMatcher().GetFilter4EA( pFilter->GetTypeName() ); 344 bTestWriter = sal_True; 345 } 346 347 sal_uLong nErr = ERRCODE_NONE; 348 if ( pFilter || bTestWriter ) 349 nErr = DetectFilter( aMedium, &pFilter ); 350 if ( nErr != ERRCODE_NONE ) 351 pFilter = NULL; 352 else if ( pOrigFilter && pFilter && pFilter->GetTypeName() == pOrigFilter->GetTypeName() ) 353 // cross filter, see above 354 pFilter = pOrigFilter; 355 } 356 357 if ( pFilter ) 358 aTypeName = pFilter->GetTypeName(); 359 else 360 aTypeName.Erase(); 361 } 362 } 363 } 364 365 if ( nIndexOfInputStream == -1 && xStream.is() ) 366 { 367 // if input stream wasn't part of the descriptor, now it should be, otherwise the content would be opend twice 368 lDescriptor.realloc( nPropertyCount + 1 ); 369 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("InputStream"); 370 lDescriptor[nPropertyCount].Value <<= xStream; 371 nPropertyCount++; 372 } 373 374 if ( nIndexOfContent == -1 && xContent.is() ) 375 { 376 // if input stream wasn't part of the descriptor, now it should be, otherwise the content would be opend twice 377 lDescriptor.realloc( nPropertyCount + 1 ); 378 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("UCBContent"); 379 lDescriptor[nPropertyCount].Value <<= xContent; 380 nPropertyCount++; 381 } 382 383 if ( bReadOnly != bWasReadOnly ) 384 { 385 if ( nIndexOfReadOnlyFlag == -1 ) 386 { 387 lDescriptor.realloc( nPropertyCount + 1 ); 388 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("ReadOnly"); 389 lDescriptor[nPropertyCount].Value <<= bReadOnly; 390 nPropertyCount++; 391 } 392 else 393 lDescriptor[nIndexOfReadOnlyFlag].Value <<= bReadOnly; 394 } 395 396 if ( !bRepairPackage && bRepairAllowed ) 397 { 398 lDescriptor.realloc( nPropertyCount + 1 ); 399 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("RepairPackage"); 400 lDescriptor[nPropertyCount].Value <<= bRepairAllowed; 401 nPropertyCount++; 402 bOpenAsTemplate = sal_True; 403 // TODO/LATER: set progress bar that should be used 404 } 405 406 if ( bOpenAsTemplate ) 407 { 408 if ( nIndexOfTemplateFlag == -1 ) 409 { 410 lDescriptor.realloc( nPropertyCount + 1 ); 411 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("AsTemplate"); 412 lDescriptor[nPropertyCount].Value <<= bOpenAsTemplate; 413 nPropertyCount++; 414 } 415 else 416 lDescriptor[nIndexOfTemplateFlag].Value <<= bOpenAsTemplate; 417 } 418 419 if ( aDocumentTitle.getLength() ) 420 { 421 // the title was set here 422 if ( nIndexOfDocumentTitle == -1 ) 423 { 424 lDescriptor.realloc( nPropertyCount + 1 ); 425 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("DocumentTitle"); 426 lDescriptor[nPropertyCount].Value <<= aDocumentTitle; 427 nPropertyCount++; 428 } 429 else 430 lDescriptor[nIndexOfDocumentTitle].Value <<= aDocumentTitle; 431 } 432 433 434 return aTypeName; 435 } 436 437 SFX_IMPL_SINGLEFACTORY( SwFilterDetect ) 438 439 /* XServiceInfo */ 440 UNOOUSTRING SAL_CALL SwFilterDetect::getImplementationName() throw( UNORUNTIMEEXCEPTION ) 441 { 442 return impl_getStaticImplementationName(); 443 } 444 \ 445 /* XServiceInfo */ 446 sal_Bool SAL_CALL SwFilterDetect::supportsService( const UNOOUSTRING& sServiceName ) throw( UNORUNTIMEEXCEPTION ) 447 { 448 UNOSEQUENCE< UNOOUSTRING > seqServiceNames = getSupportedServiceNames(); 449 const UNOOUSTRING* pArray = seqServiceNames.getConstArray(); 450 for ( sal_Int32 nCounter=0; nCounter<seqServiceNames.getLength(); nCounter++ ) 451 { 452 if ( pArray[nCounter] == sServiceName ) 453 { 454 return sal_True ; 455 } 456 } 457 return sal_False ; 458 } 459 460 /* XServiceInfo */ 461 UNOSEQUENCE< UNOOUSTRING > SAL_CALL SwFilterDetect::getSupportedServiceNames() throw( UNORUNTIMEEXCEPTION ) 462 { 463 return impl_getStaticSupportedServiceNames(); 464 } 465 466 /* Helper for XServiceInfo */ 467 UNOSEQUENCE< UNOOUSTRING > SwFilterDetect::impl_getStaticSupportedServiceNames() 468 { 469 UNOMUTEXGUARD aGuard( UNOMUTEX::getGlobalMutex() ); 470 UNOSEQUENCE< UNOOUSTRING > seqServiceNames( 3 ); 471 seqServiceNames.getArray() [0] = UNOOUSTRING::createFromAscii( "com.sun.star.frame.ExtendedTypeDetection" ); 472 seqServiceNames.getArray() [1] = UNOOUSTRING::createFromAscii( "com.sun.star.text.FormatDetector" ); 473 seqServiceNames.getArray() [2] = UNOOUSTRING::createFromAscii( "com.sun.star.text.W4WFormatDetector" ); 474 return seqServiceNames ; 475 } 476 477 /* Helper for XServiceInfo */ 478 UNOOUSTRING SwFilterDetect::impl_getStaticImplementationName() 479 { 480 return UNOOUSTRING::createFromAscii( "com.sun.star.comp.writer.FormatDetector" ); 481 } 482 483 /* Helper for registry */ 484 UNOREFERENCE< UNOXINTERFACE > SAL_CALL SwFilterDetect::impl_createInstance( const UNOREFERENCE< UNOXMULTISERVICEFACTORY >& xServiceManager ) throw( UNOEXCEPTION ) 485 { 486 return UNOREFERENCE< UNOXINTERFACE >( *new SwFilterDetect( xServiceManager ) ); 487 } 488 489