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