1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sd.hxx" 26 27 #include "sddetect.hxx" 28 29 #include <framework/interaction.hxx> 30 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 31 #include <com/sun/star/beans/PropertyValue.hpp> 32 #include <com/sun/star/frame/XFrame.hpp> 33 #include <com/sun/star/frame/XModel.hpp> 34 #include <com/sun/star/awt/XWindow.hpp> 35 #include <com/sun/star/lang/XUnoTunnel.hpp> 36 #include <comphelper/processfactory.hxx> 37 #include <com/sun/star/beans/PropertyValue.hpp> 38 #include <com/sun/star/container/XNameAccess.hpp> 39 #include <com/sun/star/io/XInputStream.hpp> 40 #include <com/sun/star/task/XInteractionHandler.hpp> 41 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> 42 #include <com/sun/star/ucb/CommandAbortedException.hpp> 43 #include <com/sun/star/ucb/InteractiveAppException.hpp> 44 #include <com/sun/star/ucb/XContent.hpp> 45 #include <com/sun/star/packages/zip/ZipIOException.hpp> 46 #include <framework/interaction.hxx> 47 #include <toolkit/helper/vclunohelper.hxx> 48 #include <ucbhelper/simpleinteractionrequest.hxx> 49 #include <svtools/filter.hxx> 50 #include <rtl/ustring.h> 51 #include <rtl/logfile.hxx> 52 #include <svl/itemset.hxx> 53 #include <vcl/window.hxx> 54 #include <svl/eitem.hxx> 55 #include <svl/stritem.hxx> 56 #include <tools/urlobj.hxx> 57 #include <vos/mutex.hxx> 58 #include <svtools/sfxecode.hxx> 59 #include <svtools/ehdl.hxx> 60 #include <sot/storinfo.hxx> 61 #include <vcl/svapp.hxx> 62 #include <sfx2/app.hxx> 63 #include <sfx2/sfxsids.hrc> 64 #include <sfx2/request.hxx> 65 #include <sfx2/docfile.hxx> 66 #include <sfx2/docfilt.hxx> 67 #include <sfx2/fcontnr.hxx> 68 #include <sfx2/brokenpackageint.hxx> 69 #include <svtools/FilterConfigItem.hxx> 70 #include <sot/storage.hxx> 71 #include <unotools/moduleoptions.hxx> 72 #include <com/sun/star/util/XArchiver.hpp> 73 #include <comphelper/processfactory.hxx> 74 75 #include "strmname.h" 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 namespace ::rtl; 86 87 SdFilterDetect::SdFilterDetect( const REFERENCE < ::com::sun::star::lang::XMultiServiceFactory >& ) 88 { 89 } 90 91 SdFilterDetect::~SdFilterDetect() 92 { 93 } 94 95 ::rtl::OUString SAL_CALL SdFilterDetect::detect( ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& lDescriptor ) throw( ::com::sun::star::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 126 for( sal_Int32 nProperty=0; nProperty<nPropertyCount; ++nProperty ) 127 { 128 // extract properties 129 if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("URL")) ) 130 { 131 lDescriptor[nProperty].Value >>= sTemp; 132 aURL = sTemp; 133 } 134 else if( !aURL.Len() && lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("FileName")) ) 135 { 136 lDescriptor[nProperty].Value >>= sTemp; 137 aURL = sTemp; 138 } 139 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("TypeName")) ) 140 { 141 lDescriptor[nProperty].Value >>= sTemp; 142 aTypeName = sTemp; 143 } 144 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("FilterName")) ) 145 { 146 lDescriptor[nProperty].Value >>= sTemp; 147 aPreselectedFilterName = sTemp; 148 149 // if the preselected filter name is not correct, it must be erased after detection 150 // remember index of property to get access to it later 151 nIndexOfFilterName = nProperty; 152 } 153 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("InputStream")) ) 154 nIndexOfInputStream = nProperty; 155 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("ReadOnly")) ) 156 nIndexOfReadOnlyFlag = nProperty; 157 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("UCBContent")) ) 158 nIndexOfContent = nProperty; 159 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("AsTemplate")) ) 160 { 161 lDescriptor[nProperty].Value >>= bOpenAsTemplate; 162 nIndexOfTemplateFlag = nProperty; 163 } 164 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("InteractionHandler")) ) 165 lDescriptor[nProperty].Value >>= xInteraction; 166 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("RepairPackage")) ) 167 lDescriptor[nProperty].Value >>= bRepairPackage; 168 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("DocumentTitle")) ) 169 nIndexOfDocumentTitle = nProperty; 170 } 171 172 // can't check the type for external filters, so set the "dont" flag accordingly 173 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 174 //SfxFilterFlags nMust = SFX_FILTER_IMPORT, nDont = SFX_FILTER_NOTINSTALLED; 175 176 SfxApplication* pApp = SFX_APP(); 177 SfxAllItemSet *pSet = new SfxAllItemSet( pApp->GetPool() ); 178 TransformParameters( SID_OPENDOC, lDescriptor, *pSet ); 179 SFX_ITEMSET_ARG( pSet, pItem, SfxBoolItem, SID_DOC_READONLY, sal_False ); 180 181 bWasReadOnly = pItem && pItem->GetValue(); 182 183 const SfxFilter* pFilter = 0; 184 String aFilterName; 185 String aPrefix = String::CreateFromAscii( "private:factory/" ); 186 if( aURL.Match( aPrefix ) == aPrefix.Len() ) 187 { 188 if( SvtModuleOptions().IsImpress() ) 189 { 190 String aPattern( aPrefix ); 191 aPattern += String::CreateFromAscii("simpress"); 192 if ( aURL.Match( aPattern ) >= aPattern.Len() ) 193 pFilter = SfxFilter::GetDefaultFilterFromFactory( aURL ); 194 } 195 196 if( !pFilter && SvtModuleOptions().IsDraw() ) 197 { 198 String aPattern( aPrefix ); 199 aPattern += String::CreateFromAscii("sdraw"); 200 if ( aURL.Match( aPattern ) >= aPattern.Len() ) 201 pFilter = SfxFilter::GetDefaultFilterFromFactory( aURL ); 202 } 203 } 204 else 205 { 206 // ctor of SfxMedium uses owner transition of ItemSet 207 SfxMedium aMedium( aURL, bWasReadOnly ? STREAM_STD_READ : STREAM_STD_READWRITE, sal_False, NULL, pSet ); 208 aMedium.UseInteractionHandler( sal_True ); 209 if ( aPreselectedFilterName.Len() ) 210 pFilter = SfxFilter::GetFilterByName( aPreselectedFilterName ); 211 else if( aTypeName.Len() ) 212 { 213 SfxFilterMatcher aMatch; 214 pFilter = aMatch.GetFilter4EA( aTypeName ); 215 } 216 217 if ( aMedium.GetErrorCode() == ERRCODE_NONE ) 218 { 219 // remember input stream and content and put them into the descriptor later 220 // should be done here since later the medium can switch to a version 221 xStream = aMedium.GetInputStream(); 222 xContent = aMedium.GetContent(); 223 bReadOnly = aMedium.IsReadOnly(); 224 sal_Bool bIsStorage = aMedium.IsStorage(); 225 226 if (aMedium.GetError() == SVSTREAM_OK) 227 { 228 if ( bIsStorage ) 229 { 230 // PowerPoint needs to be detected via StreamName, all other storage based formats are our own and can 231 // be detected by the ClipboardId, so except for the PPT filter all filters must have a ClipboardId set 232 uno::Reference < embed::XStorage > xStorage = aMedium.GetStorage( sal_False ); 233 234 //TODO/LATER: move error handling to central place! (maybe even complete own filters) 235 if ( aMedium.GetLastStorageCreationState() != ERRCODE_NONE ) 236 { 237 // error during storage creation means _here_ that the medium 238 // is broken, but we can not handle it in medium since unpossibility 239 // to create a storage does not _always_ means that the medium is broken 240 aMedium.SetError( aMedium.GetLastStorageCreationState(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); 241 if ( xInteraction.is() ) 242 { 243 OUString empty; 244 try 245 { 246 InteractiveAppException xException( empty, 247 REFERENCE< XInterface >(), 248 InteractionClassification_ERROR, 249 aMedium.GetError() ); 250 251 REFERENCE< XInteractionRequest > xRequest( 252 new ucbhelper::SimpleInteractionRequest( makeAny( xException ), 253 ucbhelper::CONTINUATION_APPROVE ) ); 254 xInteraction->handle( xRequest ); 255 } 256 catch ( Exception & ) {}; 257 } 258 } 259 else 260 { 261 if ( pFilter && !pFilter->GetFormat() ) 262 // preselected Filter has no ClipboardId -> doesn't match (see comment above) 263 pFilter = 0; 264 265 // the storage must be checked even if filter is already found, since it is deep type detection 266 // the storage can be corrupted and it will be detected here 267 try 268 { 269 String sFilterName; 270 if ( pFilter ) 271 sFilterName = pFilter->GetName(); 272 aTypeName = SfxFilter::GetTypeFromStorage( xStorage, pFilter ? pFilter->IsOwnTemplateFormat() : sal_False, &sFilterName ); 273 } 274 catch( lang::WrappedTargetException& aWrap ) 275 { 276 packages::zip::ZipIOException aZipException; 277 if ( ( aWrap.TargetException >>= aZipException ) && aTypeName.Len() ) 278 { 279 if ( xInteraction.is() ) 280 { 281 // the package is broken one 282 aDocumentTitle = aMedium.GetURLObject().getName( 283 INetURLObject::LAST_SEGMENT, 284 true, 285 INetURLObject::DECODE_WITH_CHARSET ); 286 287 if ( !bRepairPackage ) 288 { 289 // ask the user whether he wants to try to repair 290 RequestPackageReparation aRequest( aDocumentTitle ); 291 xInteraction->handle( aRequest.GetRequest() ); 292 bRepairAllowed = aRequest.isApproved(); 293 } 294 295 if ( !bRepairAllowed ) 296 { 297 // repair either not allowed or not successful 298 NotifyBrokenPackage aNotifyRequest( aDocumentTitle ); 299 xInteraction->handle( aNotifyRequest.GetRequest() ); 300 } 301 } 302 303 if ( !bRepairAllowed ) 304 { 305 aTypeName.Erase(); 306 pFilter = 0; 307 } 308 } 309 } 310 catch( uno::RuntimeException& ) 311 { 312 throw; 313 } 314 catch( uno::Exception& ) 315 { 316 aTypeName.Erase(); 317 pFilter = 0; 318 } 319 320 if ( !pFilter && aTypeName.Len() ) 321 { 322 //TODO/LATER: using this method impress is always preferred if no flat detecion has been made 323 // this should been discussed! 324 if ( SvtModuleOptions().IsImpress() ) 325 pFilter = SfxFilterMatcher( String::CreateFromAscii("simpress") ).GetFilter4EA( aTypeName ); 326 else if ( SvtModuleOptions().IsDraw() ) 327 pFilter = SfxFilterMatcher( String::CreateFromAscii("sdraw") ).GetFilter4EA( aTypeName ); 328 } 329 } 330 } 331 else 332 { 333 SvStream* pStm = aMedium.GetInStream(); 334 if ( !pStm ) 335 { 336 pFilter = 0; 337 } 338 else 339 { 340 SotStorageRef aStorage = new SotStorage ( pStm, sal_False ); 341 if ( !aStorage->GetError() ) 342 { 343 String aStreamName = UniString::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "PowerPoint Document" ) ); 344 if ( aStorage->IsStream( aStreamName ) && SvtModuleOptions().IsImpress() ) 345 { 346 String aFileName(aMedium.GetName()); 347 aFileName.ToUpperAscii(); 348 349 if( aFileName.SearchAscii( ".POT" ) == STRING_NOTFOUND ) 350 pFilter = SfxFilter::GetFilterByName( pFilterPowerPoint97); 351 else 352 pFilter = SfxFilter::GetFilterByName( pFilterPowerPoint97Template ); 353 } 354 } 355 else 356 { 357 // Vektorgraphik? 358 pStm->Seek( STREAM_SEEK_TO_BEGIN ); 359 360 const String aFileName( aMedium.GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ); 361 GraphicDescriptor aDesc( *pStm, &aFileName ); 362 GraphicFilter* pGrfFilter = GraphicFilter::GetGraphicFilter(); 363 if( !aDesc.Detect( sal_False ) ) 364 { 365 pFilter = 0; 366 if( SvtModuleOptions().IsImpress() ) 367 { 368 INetURLObject aCheckURL( aFileName ); 369 if( aCheckURL.getExtension().equalsIgnoreAsciiCaseAscii( "cgm" ) ) 370 { 371 sal_uInt8 n8; 372 pStm->Seek( STREAM_SEEK_TO_BEGIN ); 373 *pStm >> n8; 374 if ( ( n8 & 0xf0 ) == 0 ) // we are supporting binary cgm format only, so 375 { // this is a small test to exclude cgm text 376 const String aName = UniString::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "CGM - Computer Graphics Metafile" ) ); 377 SfxFilterMatcher aMatch( String::CreateFromAscii("simpress") ); 378 pFilter = aMatch.GetFilter4FilterName( aName ); 379 } 380 } 381 } 382 } 383 else 384 { 385 String aShortName( aDesc.GetImportFormatShortName( aDesc.GetFileFormat() ) ); 386 const String aName( pGrfFilter->GetImportFormatTypeName( pGrfFilter->GetImportFormatNumberForShortName( aShortName ) ) ); 387 388 if ( pFilter && aShortName.EqualsIgnoreCaseAscii( "PCD" ) ) // there is a multiple pcd selection possible 389 { 390 sal_Int32 nBase = 2; // default Base0 391 String aFilterTypeName( pFilter->GetRealTypeName() ); 392 if ( aFilterTypeName.CompareToAscii( "pcd_Photo_CD_Base4" ) == COMPARE_EQUAL ) 393 nBase = 1; 394 else if ( aFilterTypeName.CompareToAscii( "pcd_Photo_CD_Base16" ) == COMPARE_EQUAL ) 395 nBase = 0; 396 String aFilterConfigPath( RTL_CONSTASCII_USTRINGPARAM( "Office.Common/Filter/Graphic/Import/PCD" ) ); 397 FilterConfigItem aFilterConfigItem( aFilterConfigPath ); 398 aFilterConfigItem.WriteInt32( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ), nBase ); 399 } 400 401 SfxFilterMatcher aMatch( String::CreateFromAscii("sdraw") ); 402 pFilter = aMatch.GetFilter4FilterName( aName ); 403 } 404 } 405 } 406 } 407 } 408 } 409 } 410 411 if ( nIndexOfInputStream == -1 && xStream.is() ) 412 { 413 // if input stream wasn't part of the descriptor, now it should be, otherwise the content would be opend twice 414 lDescriptor.realloc( nPropertyCount + 1 ); 415 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("InputStream"); 416 lDescriptor[nPropertyCount].Value <<= xStream; 417 nPropertyCount++; 418 } 419 420 if ( nIndexOfContent == -1 && xContent.is() ) 421 { 422 // if input stream wasn't part of the descriptor, now it should be, otherwise the content would be opend twice 423 lDescriptor.realloc( nPropertyCount + 1 ); 424 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("UCBContent"); 425 lDescriptor[nPropertyCount].Value <<= xContent; 426 nPropertyCount++; 427 } 428 429 if ( bReadOnly != bWasReadOnly ) 430 { 431 if ( nIndexOfReadOnlyFlag == -1 ) 432 { 433 lDescriptor.realloc( nPropertyCount + 1 ); 434 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("ReadOnly"); 435 lDescriptor[nPropertyCount].Value <<= bReadOnly; 436 nPropertyCount++; 437 } 438 else 439 lDescriptor[nIndexOfReadOnlyFlag].Value <<= bReadOnly; 440 } 441 442 if ( !bRepairPackage && bRepairAllowed ) 443 { 444 lDescriptor.realloc( nPropertyCount + 1 ); 445 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("RepairPackage"); 446 lDescriptor[nPropertyCount].Value <<= bRepairAllowed; 447 nPropertyCount++; 448 449 bOpenAsTemplate = sal_True; 450 451 // TODO/LATER: set progress bar that should be used 452 } 453 454 if ( bOpenAsTemplate ) 455 { 456 if ( nIndexOfTemplateFlag == -1 ) 457 { 458 lDescriptor.realloc( nPropertyCount + 1 ); 459 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("AsTemplate"); 460 lDescriptor[nPropertyCount].Value <<= bOpenAsTemplate; 461 nPropertyCount++; 462 } 463 else 464 lDescriptor[nIndexOfTemplateFlag].Value <<= bOpenAsTemplate; 465 } 466 467 if ( aDocumentTitle.getLength() ) 468 { 469 // the title was set here 470 if ( nIndexOfDocumentTitle == -1 ) 471 { 472 lDescriptor.realloc( nPropertyCount + 1 ); 473 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("DocumentTitle"); 474 lDescriptor[nPropertyCount].Value <<= aDocumentTitle; 475 nPropertyCount++; 476 } 477 else 478 lDescriptor[nIndexOfDocumentTitle].Value <<= aDocumentTitle; 479 } 480 481 if ( pFilter ) 482 aTypeName = pFilter->GetTypeName(); 483 else 484 aTypeName.Erase(); 485 486 return aTypeName; 487 } 488 489 SFX_IMPL_SINGLEFACTORY( SdFilterDetect ) 490 491 /* XServiceInfo */ 492 UNOOUSTRING SAL_CALL SdFilterDetect::getImplementationName() throw( UNORUNTIMEEXCEPTION ) 493 { 494 return impl_getStaticImplementationName(); 495 } 496 \ 497 /* XServiceInfo */ 498 sal_Bool SAL_CALL SdFilterDetect::supportsService( const UNOOUSTRING& sServiceName ) throw( UNORUNTIMEEXCEPTION ) 499 { 500 UNOSEQUENCE< UNOOUSTRING > seqServiceNames = getSupportedServiceNames(); 501 const UNOOUSTRING* pArray = seqServiceNames.getConstArray(); 502 for ( sal_Int32 nCounter=0; nCounter<seqServiceNames.getLength(); nCounter++ ) 503 { 504 if ( pArray[nCounter] == sServiceName ) 505 { 506 return sal_True ; 507 } 508 } 509 return sal_False ; 510 } 511 512 /* XServiceInfo */ 513 UNOSEQUENCE< UNOOUSTRING > SAL_CALL SdFilterDetect::getSupportedServiceNames() throw( UNORUNTIMEEXCEPTION ) 514 { 515 return impl_getStaticSupportedServiceNames(); 516 } 517 518 /* Helper for XServiceInfo */ 519 UNOSEQUENCE< UNOOUSTRING > SdFilterDetect::impl_getStaticSupportedServiceNames() 520 { 521 UNOMUTEXGUARD aGuard( UNOMUTEX::getGlobalMutex() ); 522 UNOSEQUENCE< UNOOUSTRING > seqServiceNames( 1 ); 523 seqServiceNames.getArray() [0] = UNOOUSTRING::createFromAscii( "com.sun.star.frame.ExtendedTypeDetection" ); 524 return seqServiceNames ; 525 } 526 527 /* Helper for XServiceInfo */ 528 UNOOUSTRING SdFilterDetect::impl_getStaticImplementationName() 529 { 530 return UNOOUSTRING::createFromAscii( "com.sun.star.comp.draw.FormatDetector" ); 531 } 532 533 /* Helper for registry */ 534 UNOREFERENCE< UNOXINTERFACE > SAL_CALL SdFilterDetect::impl_createInstance( const UNOREFERENCE< UNOXMULTISERVICEFACTORY >& xServiceManager ) throw( UNOEXCEPTION ) 535 { 536 return UNOREFERENCE< UNOXINTERFACE >( *new SdFilterDetect( xServiceManager ) ); 537 } 538 539