1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: swdetect.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include "swdetect.hxx"
35 #include <framework/interaction.hxx>
36 #include <com/sun/star/frame/XFrame.hpp>
37 #include <com/sun/star/frame/XModel.hpp>
38 #include <com/sun/star/lang/XUnoTunnel.hpp>
39 #ifndef _UNOTOOLS_PROCESSFACTORY_HXX
40 #include <comphelper/processfactory.hxx>
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 #ifndef _TOOLKIT_UNOHLP_HXX
51 #include <toolkit/helper/vclunohelper.hxx>
53 #include <ucbhelper/simpleinteractionrequest.hxx>
54 #include <rtl/ustring.h>
55 #include <rtl/logfile.hxx>
56 #include <svtools/itemset.hxx>
57 #include <vcl/window.hxx>
58 #include <svtools/eitem.hxx>
59 #include <svtools/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 <svx/impgrf.hxx>
74 #include <svtools/FilterConfigItem.hxx>
75 #include <svtools/moduleoptions.hxx>
76 #include <com/sun/star/util/XArchiver.hpp>
77 #include <comphelper/ihwrapnofilter.hxx>
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 ::rtl::OUString
;
91 SwFilterDetect::SwFilterDetect( const REFERENCE
< lang::XMultiServiceFactory
>& /*xFactory*/ )
95 SwFilterDetect::~SwFilterDetect()
99 ::rtl::OUString SAL_CALL
SwFilterDetect::detect( uno::Sequence
< beans::PropertyValue
>& lDescriptor
) throw( uno::RuntimeException
)
101 REFERENCE
< XInputStream
> xStream
;
102 REFERENCE
< XContent
> xContent
;
103 REFERENCE
< XInteractionHandler
> xInteraction
;
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)
109 ::rtl::OUString aDocumentTitle
; // interesting only if set in this method
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
;
117 sal_Bool bRepairPackage
= sal_False
;
118 sal_Bool bRepairAllowed
= sal_False
;
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 sal_Int32 nIndexOfInteractionHandler
= -1;
131 for( sal_Int32 nProperty
=0; nProperty
<nPropertyCount
; ++nProperty
)
133 // extract properties
134 if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("URL")) )
136 lDescriptor
[nProperty
].Value
>>= sTemp
;
139 else if( !aURL
.Len() && lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("FileName")) )
141 lDescriptor
[nProperty
].Value
>>= sTemp
;
144 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("TypeName")) )
146 lDescriptor
[nProperty
].Value
>>= sTemp
;
149 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("FilterName")) )
151 lDescriptor
[nProperty
].Value
>>= sTemp
;
152 aPreselectedFilterName
= sTemp
;
154 // if the preselected filter name is not correct, it must be erased after detection
155 // remember index of property to get access to it later
156 nIndexOfFilterName
= nProperty
;
158 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("InputStream")) )
159 nIndexOfInputStream
= nProperty
;
160 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("ReadOnly")) )
161 nIndexOfReadOnlyFlag
= nProperty
;
162 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("UCBContent")) )
163 nIndexOfContent
= nProperty
;
164 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("AsTemplate")) )
166 lDescriptor
[nProperty
].Value
>>= bOpenAsTemplate
;
167 nIndexOfTemplateFlag
= nProperty
;
169 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("InteractionHandler")) )
171 lDescriptor
[nProperty
].Value
>>= xInteraction
;
172 nIndexOfInteractionHandler
= nProperty
;
174 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("RapairPackage")) )
175 lDescriptor
[nProperty
].Value
>>= bRepairPackage
;
176 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("DocumentTitle")) )
177 nIndexOfDocumentTitle
= nProperty
;
180 // can't check the type for external filters, so set the "dont" flag accordingly
181 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
182 //SfxFilterFlags nMust = SFX_FILTER_IMPORT, nDont = SFX_FILTER_NOTINSTALLED;
184 SfxApplication
* pApp
= SFX_APP();
185 SfxAllItemSet
*pSet
= new SfxAllItemSet( pApp
->GetPool() );
186 TransformParameters( SID_OPENDOC
, lDescriptor
, *pSet
);
187 SFX_ITEMSET_ARG( pSet
, pItem
, SfxBoolItem
, SID_DOC_READONLY
, FALSE
);
189 bWasReadOnly
= pItem
&& pItem
->GetValue();
191 const SfxFilter
* pFilter
= 0;
192 String aPrefix
= String::CreateFromAscii( "private:factory/" );
193 if( aURL
.Match( aPrefix
) == aPrefix
.Len() )
195 if( SvtModuleOptions().IsWriter() )
197 String
aPattern( aPrefix
);
198 aPattern
+= String::CreateFromAscii("swriter");
199 if ( aURL
.Match( aPattern
) >= aPattern
.Len() )
200 //pFilter = SfxFilter::GetDefaultFilterFromFactory( aURL );
206 // ctor of SfxMedium uses owner transition of ItemSet
207 SfxMedium
aMedium( aURL
, bWasReadOnly
? STREAM_STD_READ
: STREAM_STD_READWRITE
, FALSE
, NULL
, pSet
);
208 aMedium
.UseInteractionHandler( TRUE
);
209 if ( aMedium
.GetErrorCode() == ERRCODE_NONE
)
211 // remember input stream and content and put them into the descriptor later
212 // should be done here since later the medium can switch to a version
213 xStream
= aMedium
.GetInputStream();
214 xContent
= aMedium
.GetContent();
215 bReadOnly
= aMedium
.IsReadOnly();
217 BOOL bIsStorage
= aMedium
.IsStorage();
220 uno::Reference
< embed::XStorage
> xStorage
= aMedium
.GetStorage( sal_False
);
221 if ( aMedium
.GetLastStorageCreationState() != ERRCODE_NONE
)
223 // error during storage creation means _here_ that the medium
224 // is broken, but we can not handle it in medium since impossibility
225 // to create a storage does not _always_ means that the medium is broken
226 aMedium
.SetError( aMedium
.GetLastStorageCreationState(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ) );
227 if ( xInteraction
.is() )
232 InteractiveAppException
xException( empty
,
233 REFERENCE
< XInterface
>(),
234 InteractionClassification_ERROR
,
235 aMedium
.GetError() );
237 REFERENCE
< XInteractionRequest
> xRequest(
238 new ucbhelper::SimpleInteractionRequest( makeAny( xException
),
239 ucbhelper::CONTINUATION_APPROVE
) );
240 xInteraction
->handle( xRequest
);
242 catch ( Exception
& ) {};
247 DBG_ASSERT( xStorage
.is(), "At this point storage must exist!" );
251 const SfxFilter
* pPreFilter
= aPreselectedFilterName
.Len() ?
252 SfxFilterMatcher().GetFilter4FilterName( aPreselectedFilterName
) : aTypeName
.Len() ?
253 SfxFilterMatcher(String::CreateFromAscii("swriter")).GetFilter4EA( aTypeName
) : 0;
255 pPreFilter
= SfxFilterMatcher(String::CreateFromAscii("sweb")).GetFilter4EA( aTypeName
);
259 aFilterName
= pPreFilter
->GetName();
260 aTypeName
= pPreFilter
->GetTypeName();
263 aTypeName
= SfxFilter::GetTypeFromStorage( xStorage
, pPreFilter
? pPreFilter
->IsOwnTemplateFormat() : FALSE
, &aFilterName
);
265 catch( lang::WrappedTargetException
& aWrap
)
267 packages::zip::ZipIOException aZipException
;
269 // repairing is done only if this type is requested from outside
270 // we don't do any type detection on broken packages (f.e. because it might be impossible), so any requested
271 // type will be accepted if the user allows to repair the file
272 if ( ( aWrap
.TargetException
>>= aZipException
) && ( aTypeName
.Len() || aPreselectedFilterName
.Len() ) )
274 if ( xInteraction
.is() )
276 // the package is a broken one
277 aDocumentTitle
= aMedium
.GetURLObject().getName(
278 INetURLObject::LAST_SEGMENT
,
280 INetURLObject::DECODE_WITH_CHARSET
);
282 if ( !bRepairPackage
)
284 // ask the user whether he wants to try to repair
285 RequestPackageReparation
* pRequest
= new RequestPackageReparation( aDocumentTitle
);
286 uno::Reference
< task::XInteractionRequest
> xRequest ( pRequest
);
287 xInteraction
->handle( xRequest
);
288 bRepairAllowed
= pRequest
->isApproved();
291 if ( !bRepairAllowed
)
293 // repair either not allowed or not successful
294 NotifyBrokenPackage
* pNotifyRequest
= new NotifyBrokenPackage( aDocumentTitle
);
295 uno::Reference
< task::XInteractionRequest
> xRequest ( pNotifyRequest
);
296 xInteraction
->handle( xRequest
);
298 rtl::Reference
< ::comphelper::OIHWrapNoFilterDialog
> xHandler
= new ::comphelper::OIHWrapNoFilterDialog( xInteraction
);
299 if ( nIndexOfInteractionHandler
!= -1 )
300 lDescriptor
[nIndexOfInteractionHandler
].Value
<<= uno::Reference
< XInteractionHandler
>( static_cast< task::XInteractionHandler
* >( xHandler
.get() ) );
302 aMedium
.SetError( ERRCODE_ABORT
, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ) );
306 // no interaction, error handling as usual
307 aMedium
.SetError( ERRCODE_IO_BROKENPACKAGE
, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ) );
309 if ( !bRepairAllowed
)
312 aPreselectedFilterName
.Erase();
316 catch( uno::RuntimeException
& )
320 catch( uno::Exception
& )
323 aPreselectedFilterName
.Erase();
329 aMedium
.GetInStream();
330 if ( aMedium
.GetErrorCode() == ERRCODE_NONE
)
332 if ( aPreselectedFilterName
.Len() )
333 pFilter
= SfxFilter::GetFilterByName( aPreselectedFilterName
);
335 pFilter
= SfxFilterMatcher().GetFilter4EA( aTypeName
);
337 BOOL bTestWriter
= !pFilter
|| pFilter
->GetServiceName().EqualsAscii("com.sun.star.text.TextDocument") ||
338 pFilter
->GetServiceName().EqualsAscii("com.sun.star.text.WebDocument");
339 BOOL bTestGlobal
= !pFilter
|| pFilter
->GetServiceName().EqualsAscii("com.sun.star.text.GlobalDocument");
341 const SfxFilter
* pOrigFilter
= NULL
;
342 if ( !bTestWriter
&& !bTestGlobal
&& pFilter
)
344 // cross filter; now this should be a type detection only, not a filter detection
345 // we can simulate it by preserving the preselected filter if the type matches
346 // example: HTML filter for Calc
347 pOrigFilter
= pFilter
;
348 pFilter
= SfxFilterMatcher().GetFilter4EA( pFilter
->GetTypeName() );
352 ULONG nErr
= ERRCODE_NONE
;
353 if ( pFilter
|| bTestWriter
)
354 nErr
= DetectFilter( aMedium
, &pFilter
);
355 if ( nErr
!= ERRCODE_NONE
)
357 else if ( pOrigFilter
&& pFilter
&& pFilter
->GetTypeName() == pOrigFilter
->GetTypeName() )
358 // cross filter, see above
359 pFilter
= pOrigFilter
;
363 aTypeName
= pFilter
->GetTypeName();
370 if ( nIndexOfInputStream
== -1 && xStream
.is() )
372 // if input stream wasn't part of the descriptor, now it should be, otherwise the content would be opend twice
373 lDescriptor
.realloc( nPropertyCount
+ 1 );
374 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("InputStream");
375 lDescriptor
[nPropertyCount
].Value
<<= xStream
;
379 if ( nIndexOfContent
== -1 && xContent
.is() )
381 // if input stream wasn't part of the descriptor, now it should be, otherwise the content would be opend twice
382 lDescriptor
.realloc( nPropertyCount
+ 1 );
383 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("UCBContent");
384 lDescriptor
[nPropertyCount
].Value
<<= xContent
;
388 if ( bReadOnly
!= bWasReadOnly
)
390 if ( nIndexOfReadOnlyFlag
== -1 )
392 lDescriptor
.realloc( nPropertyCount
+ 1 );
393 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("ReadOnly");
394 lDescriptor
[nPropertyCount
].Value
<<= bReadOnly
;
398 lDescriptor
[nIndexOfReadOnlyFlag
].Value
<<= bReadOnly
;
401 if ( !bRepairPackage
&& bRepairAllowed
)
403 lDescriptor
.realloc( nPropertyCount
+ 1 );
404 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("RepairPackage");
405 lDescriptor
[nPropertyCount
].Value
<<= bRepairAllowed
;
407 bOpenAsTemplate
= sal_True
;
408 // TODO/LATER: set progress bar that should be used
411 if ( bOpenAsTemplate
)
413 if ( nIndexOfTemplateFlag
== -1 )
415 lDescriptor
.realloc( nPropertyCount
+ 1 );
416 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("AsTemplate");
417 lDescriptor
[nPropertyCount
].Value
<<= bOpenAsTemplate
;
421 lDescriptor
[nIndexOfTemplateFlag
].Value
<<= bOpenAsTemplate
;
424 if ( aDocumentTitle
.getLength() )
426 // the title was set here
427 if ( nIndexOfDocumentTitle
== -1 )
429 lDescriptor
.realloc( nPropertyCount
+ 1 );
430 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("DocumentTitle");
431 lDescriptor
[nPropertyCount
].Value
<<= aDocumentTitle
;
435 lDescriptor
[nIndexOfDocumentTitle
].Value
<<= aDocumentTitle
;
442 SFX_IMPL_SINGLEFACTORY( SwFilterDetect
)
445 UNOOUSTRING SAL_CALL
SwFilterDetect::getImplementationName() throw( UNORUNTIMEEXCEPTION
)
447 return impl_getStaticImplementationName();
451 sal_Bool SAL_CALL
SwFilterDetect::supportsService( const UNOOUSTRING
& sServiceName
) throw( UNORUNTIMEEXCEPTION
)
453 UNOSEQUENCE
< UNOOUSTRING
> seqServiceNames
= getSupportedServiceNames();
454 const UNOOUSTRING
* pArray
= seqServiceNames
.getConstArray();
455 for ( sal_Int32 nCounter
=0; nCounter
<seqServiceNames
.getLength(); nCounter
++ )
457 if ( pArray
[nCounter
] == sServiceName
)
466 UNOSEQUENCE
< UNOOUSTRING
> SAL_CALL
SwFilterDetect::getSupportedServiceNames() throw( UNORUNTIMEEXCEPTION
)
468 return impl_getStaticSupportedServiceNames();
471 /* Helper for XServiceInfo */
472 UNOSEQUENCE
< UNOOUSTRING
> SwFilterDetect::impl_getStaticSupportedServiceNames()
474 UNOMUTEXGUARD
aGuard( UNOMUTEX::getGlobalMutex() );
475 UNOSEQUENCE
< UNOOUSTRING
> seqServiceNames( 3 );
476 seqServiceNames
.getArray() [0] = UNOOUSTRING::createFromAscii( "com.sun.star.frame.ExtendedTypeDetection" );
477 seqServiceNames
.getArray() [1] = UNOOUSTRING::createFromAscii( "com.sun.star.text.FormatDetector" );
478 seqServiceNames
.getArray() [2] = UNOOUSTRING::createFromAscii( "com.sun.star.text.W4WFormatDetector" );
479 return seqServiceNames
;
482 /* Helper for XServiceInfo */
483 UNOOUSTRING
SwFilterDetect::impl_getStaticImplementationName()
485 return UNOOUSTRING::createFromAscii( "com.sun.star.comp.writer.FormatDetector" );
488 /* Helper for registry */
489 UNOREFERENCE
< UNOXINTERFACE
> SAL_CALL
SwFilterDetect::impl_createInstance( const UNOREFERENCE
< UNOXMULTISERVICEFACTORY
>& xServiceManager
) throw( UNOEXCEPTION
)
491 return UNOREFERENCE
< UNOXINTERFACE
>( *new SwFilterDetect( xServiceManager
) );