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: smdetect.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_starmath.hxx"
34 #include "smdetect.hxx"
36 #include <framework/interaction.hxx>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/beans/PropertyValue.hpp>
39 #include <com/sun/star/frame/XFrame.hpp>
40 #include <com/sun/star/frame/XModel.hpp>
41 #include <com/sun/star/awt/XWindow.hpp>
42 #include <com/sun/star/lang/XUnoTunnel.hpp>
43 #ifndef _UNOTOOLS_PROCESSFACTORY_HXX
44 #include <comphelper/processfactory.hxx>
46 #include <com/sun/star/beans/PropertyValue.hpp>
47 #include <com/sun/star/io/XInputStream.hpp>
48 #include <com/sun/star/task/XInteractionHandler.hpp>
49 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
50 #include <com/sun/star/ucb/CommandAbortedException.hpp>
51 #include <com/sun/star/ucb/InteractiveAppException.hpp>
52 #include <com/sun/star/ucb/XContent.hpp>
53 #include <com/sun/star/packages/zip/ZipIOException.hpp>
54 #include <framework/interaction.hxx>
56 #ifndef _TOOLKIT_UNOHLP_HXX
57 #include <toolkit/helper/vclunohelper.hxx>
59 #include <ucbhelper/simpleinteractionrequest.hxx>
61 #include <rtl/ustring.h>
62 #include <rtl/logfile.hxx>
63 #include <svtools/itemset.hxx>
64 #include <vcl/window.hxx>
65 #include <svtools/eitem.hxx>
66 #include <svtools/stritem.hxx>
67 #include <tools/urlobj.hxx>
68 #include <vos/mutex.hxx>
69 #include <svtools/sfxecode.hxx>
70 #include <svtools/ehdl.hxx>
71 #include <sot/storinfo.hxx>
72 #include <vcl/svapp.hxx>
73 #include <sfx2/app.hxx>
74 #include <sfx2/sfxsids.hrc>
75 #include <sfx2/request.hxx>
76 #include <sfx2/docfile.hxx>
77 #include <sfx2/docfilt.hxx>
78 #include <sfx2/fcontnr.hxx>
79 #include <sfx2/brokenpackageint.hxx>
81 #include "document.hxx"
82 #include "eqnolefilehdr.hxx"
85 using namespace ::com::sun::star
;
86 using namespace ::com::sun::star::uno
;
87 using namespace ::com::sun::star::io
;
88 using namespace ::com::sun::star::frame
;
89 using namespace ::com::sun::star::task
;
90 using namespace ::com::sun::star::beans
;
91 using namespace ::com::sun::star::lang
;
92 using namespace ::com::sun::star::ucb
;
93 using namespace ::rtl
;
95 SmFilterDetect::SmFilterDetect( const REFERENCE
< ::com::sun::star::lang::XMultiServiceFactory
>& /*xFactory*/ )
99 SmFilterDetect::~SmFilterDetect()
103 ::rtl::OUString SAL_CALL
SmFilterDetect::detect( ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& lDescriptor
) throw( ::com::sun::star::uno::RuntimeException
)
105 REFERENCE
< XInputStream
> xStream
;
106 REFERENCE
< XContent
> xContent
;
107 REFERENCE
< XInteractionHandler
> xInteraction
;
109 ::rtl::OUString sTemp
;
110 String aTypeName
; // a name describing the type (from MediaDescriptor, usually from flat detection)
111 String aPreselectedFilterName
; // a name describing the filter to use (from MediaDescriptor, usually from UI action)
113 ::rtl::OUString aDocumentTitle
; // interesting only if set in this method
115 // opening as template is done when a parameter tells to do so and a template filter can be detected
116 // (otherwise no valid filter would be found) or if the detected filter is a template filter and
117 // there is no parameter that forbids to open as template
118 sal_Bool bOpenAsTemplate
= sal_False
;
119 sal_Bool bWasReadOnly
= sal_False
, bReadOnly
= sal_False
;
121 sal_Bool bRepairPackage
= sal_False
;
122 sal_Bool bRepairAllowed
= sal_False
;
124 // now some parameters that can already be in the array, but may be overwritten or new inserted here
125 // remember their indices in the case new values must be added to the array
126 sal_Int32 nPropertyCount
= lDescriptor
.getLength();
127 sal_Int32 nIndexOfFilterName
= -1;
128 sal_Int32 nIndexOfInputStream
= -1;
129 sal_Int32 nIndexOfContent
= -1;
130 sal_Int32 nIndexOfReadOnlyFlag
= -1;
131 sal_Int32 nIndexOfTemplateFlag
= -1;
132 sal_Int32 nIndexOfDocumentTitle
= -1;
134 for( sal_Int32 nProperty
=0; nProperty
<nPropertyCount
; ++nProperty
)
136 // extract properties
137 if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("URL")) )
139 lDescriptor
[nProperty
].Value
>>= sTemp
;
142 else if( !aURL
.Len() && lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("FileName")) )
144 lDescriptor
[nProperty
].Value
>>= sTemp
;
147 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("TypeName")) )
149 lDescriptor
[nProperty
].Value
>>= sTemp
;
152 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("FilterName")) )
154 lDescriptor
[nProperty
].Value
>>= sTemp
;
155 aPreselectedFilterName
= sTemp
;
157 // if the preselected filter name is not correct, it must be erased after detection
158 // remember index of property to get access to it later
159 nIndexOfFilterName
= nProperty
;
161 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("InputStream")) )
162 nIndexOfInputStream
= nProperty
;
163 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("ReadOnly")) )
164 nIndexOfReadOnlyFlag
= nProperty
;
165 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("UCBContent")) )
166 nIndexOfContent
= nProperty
;
167 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("AsTemplate")) )
169 lDescriptor
[nProperty
].Value
>>= bOpenAsTemplate
;
170 nIndexOfTemplateFlag
= nProperty
;
172 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("InteractionHandler")) )
173 lDescriptor
[nProperty
].Value
>>= xInteraction
;
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();
192 String aPrefix
= String::CreateFromAscii( "private:factory/" );
193 if( aURL
.Match( aPrefix
) == aPrefix
.Len() )
195 const SfxFilter
* pFilter
= 0;
196 String
aPattern( aPrefix
);
197 aPattern
+= String::CreateFromAscii("smath");
198 if ( aURL
.Match( aPattern
) >= aPattern
.Len() )
200 pFilter
= SfxFilter::GetDefaultFilterFromFactory( aURL
);
201 aTypeName
= pFilter
->GetTypeName();
202 aFilterName
= pFilter
->GetName();
207 // ctor of SfxMedium uses owner transition of ItemSet
208 SfxMedium
aMedium( aURL
, bWasReadOnly
? STREAM_STD_READ
: STREAM_STD_READWRITE
, FALSE
, NULL
, pSet
);
209 aMedium
.UseInteractionHandler( TRUE
);
211 BOOL bIsStorage
= aMedium
.IsStorage();
212 if ( aMedium
.GetErrorCode() == ERRCODE_NONE
)
214 // remember input stream and content and put them into the descriptor later
215 // should be done here since later the medium can switch to a version
216 xStream
= aMedium
.GetInputStream();
217 xContent
= aMedium
.GetContent();
218 bReadOnly
= aMedium
.IsReadOnly();
222 //TODO/LATER: factor this out!
223 uno::Reference
< embed::XStorage
> xStorage
= aMedium
.GetStorage();
224 if ( aMedium
.GetLastStorageCreationState() != ERRCODE_NONE
)
226 // error during storage creation means _here_ that the medium
227 // is broken, but we can not handle it in medium since unpossibility
228 // to create a storage does not _always_ means that the medium is broken
229 aMedium
.SetError( aMedium
.GetLastStorageCreationState() );
230 if ( xInteraction
.is() )
235 InteractiveAppException
xException( empty
,
236 REFERENCE
< XInterface
>(),
237 InteractionClassification_ERROR
,
238 aMedium
.GetError() );
240 REFERENCE
< XInteractionRequest
> xRequest(
241 new ucbhelper::SimpleInteractionRequest( makeAny( xException
),
242 ucbhelper::CONTINUATION_APPROVE
) );
243 xInteraction
->handle( xRequest
);
245 catch ( Exception
& ) {};
254 const SfxFilter
* pFilter
= aPreselectedFilterName
.Len() ?
255 SfxFilterMatcher().GetFilter4FilterName( aPreselectedFilterName
) : aTypeName
.Len() ?
256 SfxFilterMatcher(String::CreateFromAscii("smath")).GetFilter4EA( aTypeName
) : 0;
257 String aTmpFilterName
;
259 aTmpFilterName
= pFilter
->GetName();
260 aTypeName
= SfxFilter::GetTypeFromStorage( xStorage
, pFilter
? pFilter
->IsAllowedAsTemplate() : FALSE
, &aTmpFilterName
);
262 catch( lang::WrappedTargetException
& aWrap
)
264 packages::zip::ZipIOException aZipException
;
266 // repairing is done only if this type is requested from outside
267 if ( ( aWrap
.TargetException
>>= aZipException
) && aTypeName
.Len() )
269 if ( xInteraction
.is() )
271 // the package is broken one
272 aDocumentTitle
= aMedium
.GetURLObject().getName(
273 INetURLObject::LAST_SEGMENT
,
275 INetURLObject::DECODE_WITH_CHARSET
);
277 if ( !bRepairPackage
)
279 // ask the user whether he wants to try to repair
280 RequestPackageReparation
* pRequest
= new RequestPackageReparation( aDocumentTitle
);
281 uno::Reference
< task::XInteractionRequest
> xRequest ( pRequest
);
283 xInteraction
->handle( xRequest
);
285 bRepairAllowed
= pRequest
->isApproved();
288 if ( !bRepairAllowed
)
290 // repair either not allowed or not successful
291 NotifyBrokenPackage
* pNotifyRequest
= new NotifyBrokenPackage( aDocumentTitle
);
292 uno::Reference
< task::XInteractionRequest
> xRequest ( pNotifyRequest
);
293 xInteraction
->handle( xRequest
);
297 if ( !bRepairAllowed
)
301 catch( uno::RuntimeException
& )
305 catch( uno::Exception
& )
310 if ( aTypeName
.Len() )
312 const SfxFilter
* pFilter
=
313 SfxFilterMatcher( String::CreateFromAscii("smath") ).GetFilter4EA( aTypeName
);
315 aFilterName
= pFilter
->GetName();
321 //Test to see if this begins with xml and if so run it through
322 //the MathML filter. There are all sorts of things wrong with
323 //this approach, to be fixed at a better level than here
324 SvStream
*pStrm
= aMedium
.GetInStream();
326 if (pStrm
&& !pStrm
->GetError())
328 SotStorageRef aStorage
= new SotStorage ( pStrm
, FALSE
);
329 if ( !aStorage
->GetError() )
331 if ( aStorage
->IsStream( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "Equation Native" ) ) ) )
334 if (GetMathTypeVersion( aStorage
, nVersion
) && nVersion
<=3)
335 aTypeName
.AssignAscii( "math_MathType_3x" );
340 const USHORT nSize
= 5;
341 sal_Char aBuffer
[nSize
+1];
343 pStrm
->Seek( STREAM_SEEK_TO_BEGIN
);
344 ULONG nBytesRead
= pStrm
->Read( aBuffer
, nSize
);
345 if (nBytesRead
== nSize
)
347 if (0 == strncmp( "<?xml",aBuffer
,nSize
))
349 static const sal_Char sFltrNm_2
[] = MATHML_XML
;
350 static const sal_Char sTypeNm_2
[] = "math_MathML_XML_Math";
351 aFilterName
.AssignAscii( sFltrNm_2
);
352 aTypeName
.AssignAscii( sTypeNm_2
);
357 if ( aTypeName
.Len() )
359 const SfxFilter
* pFilt
= SfxFilterMatcher( String::CreateFromAscii("smath") ).GetFilter4EA( aTypeName
);
361 aFilterName
= pFilt
->GetName();
368 if ( nIndexOfInputStream
== -1 && xStream
.is() )
370 // if input stream wasn't part of the descriptor, now it should be, otherwise the content would be opend twice
371 lDescriptor
.realloc( nPropertyCount
+ 1 );
372 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("InputStream");
373 lDescriptor
[nPropertyCount
].Value
<<= xStream
;
377 if ( nIndexOfContent
== -1 && xContent
.is() )
379 // if input stream wasn't part of the descriptor, now it should be, otherwise the content would be opend twice
380 lDescriptor
.realloc( nPropertyCount
+ 1 );
381 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("UCBContent");
382 lDescriptor
[nPropertyCount
].Value
<<= xContent
;
386 if ( bReadOnly
!= bWasReadOnly
)
388 if ( nIndexOfReadOnlyFlag
== -1 )
390 lDescriptor
.realloc( nPropertyCount
+ 1 );
391 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("ReadOnly");
392 lDescriptor
[nPropertyCount
].Value
<<= bReadOnly
;
396 lDescriptor
[nIndexOfReadOnlyFlag
].Value
<<= bReadOnly
;
399 if ( !bRepairPackage
&& bRepairAllowed
)
401 lDescriptor
.realloc( nPropertyCount
+ 1 );
402 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("RepairPackage");
403 lDescriptor
[nPropertyCount
].Value
<<= bRepairAllowed
;
406 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
;
438 if ( !aFilterName
.Len() )
444 SFX_IMPL_SINGLEFACTORY( SmFilterDetect
)
447 UNOOUSTRING SAL_CALL
SmFilterDetect::getImplementationName() throw( UNORUNTIMEEXCEPTION
)
449 return impl_getStaticImplementationName();
453 sal_Bool SAL_CALL
SmFilterDetect::supportsService( const UNOOUSTRING
& sServiceName
) throw( UNORUNTIMEEXCEPTION
)
455 UNOSEQUENCE
< UNOOUSTRING
> seqServiceNames
= getSupportedServiceNames();
456 const UNOOUSTRING
* pArray
= seqServiceNames
.getConstArray();
457 for ( sal_Int32 nCounter
=0; nCounter
<seqServiceNames
.getLength(); nCounter
++ )
459 if ( pArray
[nCounter
] == sServiceName
)
468 UNOSEQUENCE
< UNOOUSTRING
> SAL_CALL
SmFilterDetect::getSupportedServiceNames() throw( UNORUNTIMEEXCEPTION
)
470 return impl_getStaticSupportedServiceNames();
473 /* Helper for XServiceInfo */
474 UNOSEQUENCE
< UNOOUSTRING
> SmFilterDetect::impl_getStaticSupportedServiceNames()
476 UNOMUTEXGUARD
aGuard( UNOMUTEX::getGlobalMutex() );
477 UNOSEQUENCE
< UNOOUSTRING
> seqServiceNames( 1 );
478 seqServiceNames
.getArray() [0] = UNOOUSTRING::createFromAscii( "com.sun.star.frame.ExtendedTypeDetection" );
479 return seqServiceNames
;
482 /* Helper for XServiceInfo */
483 UNOOUSTRING
SmFilterDetect::impl_getStaticImplementationName()
485 return UNOOUSTRING::createFromAscii( "com.sun.star.comp.math.FormatDetector" );
488 /* Helper for registry */
489 UNOREFERENCE
< UNOXINTERFACE
> SAL_CALL
SmFilterDetect::impl_createInstance( const UNOREFERENCE
< UNOXMULTISERVICEFACTORY
>& xServiceManager
) throw( UNOEXCEPTION
)
491 return UNOREFERENCE
< UNOXINTERFACE
>( *new SmFilterDetect( xServiceManager
) );