1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_starmath.hxx"
31 #include "smdetect.hxx"
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 #ifndef _UNOTOOLS_PROCESSFACTORY_HXX
41 #include <comphelper/processfactory.hxx>
43 #include <com/sun/star/beans/PropertyValue.hpp>
44 #include <com/sun/star/io/XInputStream.hpp>
45 #include <com/sun/star/task/XInteractionHandler.hpp>
46 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
47 #include <com/sun/star/ucb/CommandAbortedException.hpp>
48 #include <com/sun/star/ucb/InteractiveAppException.hpp>
49 #include <com/sun/star/ucb/XContent.hpp>
50 #include <com/sun/star/packages/zip/ZipIOException.hpp>
51 #include <framework/interaction.hxx>
53 #ifndef _TOOLKIT_UNOHLP_HXX
54 #include <toolkit/helper/vclunohelper.hxx>
56 #include <ucbhelper/simpleinteractionrequest.hxx>
58 #include <rtl/ustring.h>
59 #include <rtl/logfile.hxx>
60 #include <svl/itemset.hxx>
61 #include <vcl/window.hxx>
62 #include <svl/eitem.hxx>
63 #include <svl/stritem.hxx>
64 #include <tools/urlobj.hxx>
65 #include <vos/mutex.hxx>
66 #include <svtools/sfxecode.hxx>
67 #include <svtools/ehdl.hxx>
68 #include <sot/storinfo.hxx>
69 #include <vcl/svapp.hxx>
70 #include <sfx2/app.hxx>
71 #include <sfx2/sfxsids.hrc>
72 #include <sfx2/request.hxx>
73 #include <sfx2/docfile.hxx>
74 #include <sfx2/docfilt.hxx>
75 #include <sfx2/fcontnr.hxx>
76 #include <sfx2/brokenpackageint.hxx>
78 #include "document.hxx"
79 #include "eqnolefilehdr.hxx"
82 using namespace ::com::sun::star
;
83 using namespace ::com::sun::star::uno
;
84 using namespace ::com::sun::star::io
;
85 using namespace ::com::sun::star::frame
;
86 using namespace ::com::sun::star::task
;
87 using namespace ::com::sun::star::beans
;
88 using namespace ::com::sun::star::lang
;
89 using namespace ::com::sun::star::ucb
;
90 using namespace ::rtl
;
92 SmFilterDetect::SmFilterDetect( const REFERENCE
< ::com::sun::star::lang::XMultiServiceFactory
>& /*xFactory*/ )
96 SmFilterDetect::~SmFilterDetect()
100 ::rtl::OUString SAL_CALL
SmFilterDetect::detect( ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& lDescriptor
) throw( ::com::sun::star::uno::RuntimeException
)
102 REFERENCE
< XInputStream
> xStream
;
103 REFERENCE
< XContent
> xContent
;
104 REFERENCE
< XInteractionHandler
> xInteraction
;
106 ::rtl::OUString sTemp
;
107 String aTypeName
; // a name describing the type (from MediaDescriptor, usually from flat detection)
108 String aPreselectedFilterName
; // a name describing the filter to use (from MediaDescriptor, usually from UI action)
110 ::rtl::OUString aDocumentTitle
; // interesting only if set in this method
112 // opening as template is done when a parameter tells to do so and a template filter can be detected
113 // (otherwise no valid filter would be found) or if the detected filter is a template filter and
114 // there is no parameter that forbids to open as template
115 sal_Bool bOpenAsTemplate
= sal_False
;
116 sal_Bool bWasReadOnly
= sal_False
, bReadOnly
= sal_False
;
118 sal_Bool bRepairPackage
= sal_False
;
119 sal_Bool bRepairAllowed
= sal_False
;
121 // now some parameters that can already be in the array, but may be overwritten or new inserted here
122 // remember their indices in the case new values must be added to the array
123 sal_Int32 nPropertyCount
= lDescriptor
.getLength();
124 sal_Int32 nIndexOfFilterName
= -1;
125 sal_Int32 nIndexOfInputStream
= -1;
126 sal_Int32 nIndexOfContent
= -1;
127 sal_Int32 nIndexOfReadOnlyFlag
= -1;
128 sal_Int32 nIndexOfTemplateFlag
= -1;
129 sal_Int32 nIndexOfDocumentTitle
= -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")) )
170 lDescriptor
[nProperty
].Value
>>= xInteraction
;
171 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("RepairPackage")) )
172 lDescriptor
[nProperty
].Value
>>= bRepairPackage
;
173 else if( lDescriptor
[nProperty
].Name
== OUString(RTL_CONSTASCII_USTRINGPARAM("DocumentTitle")) )
174 nIndexOfDocumentTitle
= nProperty
;
177 // can't check the type for external filters, so set the "dont" flag accordingly
178 ::vos::OGuard
aGuard( Application::GetSolarMutex() );
179 //SfxFilterFlags nMust = SFX_FILTER_IMPORT, nDont = SFX_FILTER_NOTINSTALLED;
181 SfxApplication
* pApp
= SFX_APP();
182 SfxAllItemSet
*pSet
= new SfxAllItemSet( pApp
->GetPool() );
183 TransformParameters( SID_OPENDOC
, lDescriptor
, *pSet
);
184 SFX_ITEMSET_ARG( pSet
, pItem
, SfxBoolItem
, SID_DOC_READONLY
, FALSE
);
186 bWasReadOnly
= pItem
&& pItem
->GetValue();
189 String aPrefix
= String::CreateFromAscii( "private:factory/" );
190 if( aURL
.Match( aPrefix
) == aPrefix
.Len() )
192 const SfxFilter
* pFilter
= 0;
193 String
aPattern( aPrefix
);
194 aPattern
+= String::CreateFromAscii("smath");
195 if ( aURL
.Match( aPattern
) >= aPattern
.Len() )
197 pFilter
= SfxFilter::GetDefaultFilterFromFactory( aURL
);
198 aTypeName
= pFilter
->GetTypeName();
199 aFilterName
= pFilter
->GetName();
204 // ctor of SfxMedium uses owner transition of ItemSet
205 SfxMedium
aMedium( aURL
, bWasReadOnly
? STREAM_STD_READ
: STREAM_STD_READWRITE
, FALSE
, NULL
, pSet
);
206 aMedium
.UseInteractionHandler( TRUE
);
208 BOOL bIsStorage
= aMedium
.IsStorage();
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();
219 //TODO/LATER: factor this out!
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 unpossibility
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
& ) {};
251 const SfxFilter
* pFilter
= aPreselectedFilterName
.Len() ?
252 SfxFilterMatcher().GetFilter4FilterName( aPreselectedFilterName
) : aTypeName
.Len() ?
253 SfxFilterMatcher(String::CreateFromAscii("smath")).GetFilter4EA( aTypeName
) : 0;
254 String aTmpFilterName
;
256 aTmpFilterName
= pFilter
->GetName();
257 aTypeName
= SfxFilter::GetTypeFromStorage( xStorage
, pFilter
? pFilter
->IsAllowedAsTemplate() : FALSE
, &aTmpFilterName
);
259 catch( lang::WrappedTargetException
& aWrap
)
261 packages::zip::ZipIOException aZipException
;
263 // repairing is done only if this type is requested from outside
264 if ( ( aWrap
.TargetException
>>= aZipException
) && aTypeName
.Len() )
266 if ( xInteraction
.is() )
268 // the package is broken one
269 aDocumentTitle
= aMedium
.GetURLObject().getName(
270 INetURLObject::LAST_SEGMENT
,
272 INetURLObject::DECODE_WITH_CHARSET
);
274 if ( !bRepairPackage
)
276 // ask the user whether he wants to try to repair
277 RequestPackageReparation
* pRequest
= new RequestPackageReparation( aDocumentTitle
);
278 uno::Reference
< task::XInteractionRequest
> xRequest ( pRequest
);
280 xInteraction
->handle( xRequest
);
282 bRepairAllowed
= pRequest
->isApproved();
285 if ( !bRepairAllowed
)
287 // repair either not allowed or not successful
288 NotifyBrokenPackage
* pNotifyRequest
= new NotifyBrokenPackage( aDocumentTitle
);
289 uno::Reference
< task::XInteractionRequest
> xRequest ( pNotifyRequest
);
290 xInteraction
->handle( xRequest
);
294 if ( !bRepairAllowed
)
298 catch( uno::RuntimeException
& )
302 catch( uno::Exception
& )
307 if ( aTypeName
.Len() )
309 const SfxFilter
* pFilter
=
310 SfxFilterMatcher( String::CreateFromAscii("smath") ).GetFilter4EA( aTypeName
);
312 aFilterName
= pFilter
->GetName();
318 //Test to see if this begins with xml and if so run it through
319 //the MathML filter. There are all sorts of things wrong with
320 //this approach, to be fixed at a better level than here
321 SvStream
*pStrm
= aMedium
.GetInStream();
323 if (pStrm
&& !pStrm
->GetError())
325 SotStorageRef aStorage
= new SotStorage ( pStrm
, FALSE
);
326 if ( !aStorage
->GetError() )
328 if ( aStorage
->IsStream( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "Equation Native" ) ) ) )
331 if (GetMathTypeVersion( aStorage
, nVersion
) && nVersion
<=3)
332 aTypeName
.AssignAscii( "math_MathType_3x" );
337 const USHORT nSize
= 5;
338 sal_Char aBuffer
[nSize
+1];
340 pStrm
->Seek( STREAM_SEEK_TO_BEGIN
);
341 ULONG nBytesRead
= pStrm
->Read( aBuffer
, nSize
);
342 if (nBytesRead
== nSize
)
344 if (0 == strncmp( "<?xml",aBuffer
,nSize
))
346 static const sal_Char sFltrNm_2
[] = MATHML_XML
;
347 static const sal_Char sTypeNm_2
[] = "math_MathML_XML_Math";
348 aFilterName
.AssignAscii( sFltrNm_2
);
349 aTypeName
.AssignAscii( sTypeNm_2
);
354 if ( aTypeName
.Len() )
356 const SfxFilter
* pFilt
= SfxFilterMatcher( String::CreateFromAscii("smath") ).GetFilter4EA( aTypeName
);
358 aFilterName
= pFilt
->GetName();
365 if ( nIndexOfInputStream
== -1 && xStream
.is() )
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
;
374 if ( nIndexOfContent
== -1 && xContent
.is() )
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
;
383 if ( bReadOnly
!= bWasReadOnly
)
385 if ( nIndexOfReadOnlyFlag
== -1 )
387 lDescriptor
.realloc( nPropertyCount
+ 1 );
388 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("ReadOnly");
389 lDescriptor
[nPropertyCount
].Value
<<= bReadOnly
;
393 lDescriptor
[nIndexOfReadOnlyFlag
].Value
<<= bReadOnly
;
396 if ( !bRepairPackage
&& bRepairAllowed
)
398 lDescriptor
.realloc( nPropertyCount
+ 1 );
399 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("RepairPackage");
400 lDescriptor
[nPropertyCount
].Value
<<= bRepairAllowed
;
403 bOpenAsTemplate
= sal_True
;
405 // TODO/LATER: set progress bar that should be used
408 if ( bOpenAsTemplate
)
410 if ( nIndexOfTemplateFlag
== -1 )
412 lDescriptor
.realloc( nPropertyCount
+ 1 );
413 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("AsTemplate");
414 lDescriptor
[nPropertyCount
].Value
<<= bOpenAsTemplate
;
418 lDescriptor
[nIndexOfTemplateFlag
].Value
<<= bOpenAsTemplate
;
421 if ( aDocumentTitle
.getLength() )
423 // the title was set here
424 if ( nIndexOfDocumentTitle
== -1 )
426 lDescriptor
.realloc( nPropertyCount
+ 1 );
427 lDescriptor
[nPropertyCount
].Name
= ::rtl::OUString::createFromAscii("DocumentTitle");
428 lDescriptor
[nPropertyCount
].Value
<<= aDocumentTitle
;
432 lDescriptor
[nIndexOfDocumentTitle
].Value
<<= aDocumentTitle
;
435 if ( !aFilterName
.Len() )
441 SFX_IMPL_SINGLEFACTORY( SmFilterDetect
)
444 UNOOUSTRING SAL_CALL
SmFilterDetect::getImplementationName() throw( UNORUNTIMEEXCEPTION
)
446 return impl_getStaticImplementationName();
450 sal_Bool SAL_CALL
SmFilterDetect::supportsService( const UNOOUSTRING
& sServiceName
) throw( UNORUNTIMEEXCEPTION
)
452 UNOSEQUENCE
< UNOOUSTRING
> seqServiceNames
= getSupportedServiceNames();
453 const UNOOUSTRING
* pArray
= seqServiceNames
.getConstArray();
454 for ( sal_Int32 nCounter
=0; nCounter
<seqServiceNames
.getLength(); nCounter
++ )
456 if ( pArray
[nCounter
] == sServiceName
)
465 UNOSEQUENCE
< UNOOUSTRING
> SAL_CALL
SmFilterDetect::getSupportedServiceNames() throw( UNORUNTIMEEXCEPTION
)
467 return impl_getStaticSupportedServiceNames();
470 /* Helper for XServiceInfo */
471 UNOSEQUENCE
< UNOOUSTRING
> SmFilterDetect::impl_getStaticSupportedServiceNames()
473 UNOMUTEXGUARD
aGuard( UNOMUTEX::getGlobalMutex() );
474 UNOSEQUENCE
< UNOOUSTRING
> seqServiceNames( 1 );
475 seqServiceNames
.getArray() [0] = UNOOUSTRING::createFromAscii( "com.sun.star.frame.ExtendedTypeDetection" );
476 return seqServiceNames
;
479 /* Helper for XServiceInfo */
480 UNOOUSTRING
SmFilterDetect::impl_getStaticImplementationName()
482 return UNOOUSTRING::createFromAscii( "com.sun.star.comp.math.FormatDetector" );
485 /* Helper for registry */
486 UNOREFERENCE
< UNOXINTERFACE
> SAL_CALL
SmFilterDetect::impl_createInstance( const UNOREFERENCE
< UNOXMULTISERVICEFACTORY
>& xServiceManager
) throw( UNOEXCEPTION
)
488 return UNOREFERENCE
< UNOXINTERFACE
>( *new SmFilterDetect( xServiceManager
) );