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_starmath.hxx" 30 31 #include "smdetect.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 #ifndef _UNOTOOLS_PROCESSFACTORY_HXX 41 #include <comphelper/processfactory.hxx> 42 #endif 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> 52 53 #ifndef _TOOLKIT_UNOHLP_HXX 54 #include <toolkit/helper/vclunohelper.hxx> 55 #endif 56 #include <ucbhelper/simpleinteractionrequest.hxx> 57 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> 77 78 #include "document.hxx" 79 #include "eqnolefilehdr.hxx" 80 81 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; 91 92 SmFilterDetect::SmFilterDetect( const REFERENCE < ::com::sun::star::lang::XMultiServiceFactory >& /*xFactory*/ ) 93 { 94 } 95 96 SmFilterDetect::~SmFilterDetect() 97 { 98 } 99 100 ::rtl::OUString SAL_CALL SmFilterDetect::detect( ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& lDescriptor ) throw( ::com::sun::star::uno::RuntimeException ) 101 { 102 REFERENCE< XInputStream > xStream; 103 REFERENCE< XContent > xContent; 104 REFERENCE< XInteractionHandler > xInteraction; 105 String aURL; 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) 109 110 ::rtl::OUString aDocumentTitle; // interesting only if set in this method 111 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; 117 118 sal_Bool bRepairPackage = sal_False; 119 sal_Bool bRepairAllowed = sal_False; 120 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; 130 131 for( sal_Int32 nProperty=0; nProperty<nPropertyCount; ++nProperty ) 132 { 133 // extract properties 134 if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("URL")) ) 135 { 136 lDescriptor[nProperty].Value >>= sTemp; 137 aURL = sTemp; 138 } 139 else if( !aURL.Len() && lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("FileName")) ) 140 { 141 lDescriptor[nProperty].Value >>= sTemp; 142 aURL = sTemp; 143 } 144 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("TypeName")) ) 145 { 146 lDescriptor[nProperty].Value >>= sTemp; 147 aTypeName = sTemp; 148 } 149 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("FilterName")) ) 150 { 151 lDescriptor[nProperty].Value >>= sTemp; 152 aPreselectedFilterName = sTemp; 153 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; 157 } 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")) ) 165 { 166 lDescriptor[nProperty].Value >>= bOpenAsTemplate; 167 nIndexOfTemplateFlag = nProperty; 168 } 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; 175 } 176 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; 180 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, sal_False ); 185 186 bWasReadOnly = pItem && pItem->GetValue(); 187 188 String aFilterName; 189 String aPrefix = String::CreateFromAscii( "private:factory/" ); 190 if( aURL.Match( aPrefix ) == aPrefix.Len() ) 191 { 192 const SfxFilter* pFilter = 0; 193 String aPattern( aPrefix ); 194 aPattern += String::CreateFromAscii("smath"); 195 if ( aURL.Match( aPattern ) >= aPattern.Len() ) 196 { 197 pFilter = SfxFilter::GetDefaultFilterFromFactory( aURL ); 198 aTypeName = pFilter->GetTypeName(); 199 aFilterName = pFilter->GetName(); 200 } 201 } 202 else 203 { 204 // ctor of SfxMedium uses owner transition of ItemSet 205 SfxMedium aMedium( aURL, bWasReadOnly ? STREAM_STD_READ : STREAM_STD_READWRITE, sal_False, NULL, pSet ); 206 aMedium.UseInteractionHandler( sal_True ); 207 208 sal_Bool bIsStorage = aMedium.IsStorage(); 209 if ( aMedium.GetErrorCode() == ERRCODE_NONE ) 210 { 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(); 216 217 if ( bIsStorage ) 218 { 219 //TODO/LATER: factor this out! 220 uno::Reference < embed::XStorage > xStorage = aMedium.GetStorage( sal_False ); 221 if ( aMedium.GetLastStorageCreationState() != ERRCODE_NONE ) 222 { 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() ) 228 { 229 OUString empty; 230 try 231 { 232 InteractiveAppException xException( empty, 233 REFERENCE< XInterface >(), 234 InteractionClassification_ERROR, 235 aMedium.GetError() ); 236 237 REFERENCE< XInteractionRequest > xRequest( 238 new ucbhelper::SimpleInteractionRequest( makeAny( xException ), 239 ucbhelper::CONTINUATION_APPROVE ) ); 240 xInteraction->handle( xRequest ); 241 } 242 catch ( Exception & ) {}; 243 } 244 } 245 else 246 { 247 aFilterName.Erase(); 248 249 try 250 { 251 const SfxFilter* pFilter = aPreselectedFilterName.Len() ? 252 SfxFilterMatcher().GetFilter4FilterName( aPreselectedFilterName ) : aTypeName.Len() ? 253 SfxFilterMatcher(String::CreateFromAscii("smath")).GetFilter4EA( aTypeName ) : 0; 254 String aTmpFilterName; 255 if ( pFilter ) 256 aTmpFilterName = pFilter->GetName(); 257 aTypeName = SfxFilter::GetTypeFromStorage( xStorage, pFilter ? pFilter->IsAllowedAsTemplate() : sal_False, &aTmpFilterName ); 258 } 259 catch( lang::WrappedTargetException& aWrap ) 260 { 261 packages::zip::ZipIOException aZipException; 262 263 // repairing is done only if this type is requested from outside 264 if ( ( aWrap.TargetException >>= aZipException ) && aTypeName.Len() ) 265 { 266 if ( xInteraction.is() ) 267 { 268 // the package is broken one 269 aDocumentTitle = aMedium.GetURLObject().getName( 270 INetURLObject::LAST_SEGMENT, 271 true, 272 INetURLObject::DECODE_WITH_CHARSET ); 273 274 if ( !bRepairPackage ) 275 { 276 // ask the user whether he wants to try to repair 277 RequestPackageReparation aRequest( aDocumentTitle ); 278 xInteraction->handle( aRequest.GetRequest() ); 279 bRepairAllowed = aRequest.isApproved(); 280 } 281 282 if ( !bRepairAllowed ) 283 { 284 // repair either not allowed or not successful 285 NotifyBrokenPackage aNotifyRequest( aDocumentTitle ); 286 xInteraction->handle( aNotifyRequest.GetRequest() ); 287 } 288 } 289 290 if ( !bRepairAllowed ) 291 aTypeName.Erase(); 292 } 293 } 294 catch( uno::RuntimeException& ) 295 { 296 throw; 297 } 298 catch( uno::Exception& ) 299 { 300 aTypeName.Erase(); 301 } 302 303 if ( aTypeName.Len() ) 304 { 305 const SfxFilter* pFilter = 306 SfxFilterMatcher( String::CreateFromAscii("smath") ).GetFilter4EA( aTypeName ); 307 if ( pFilter ) 308 aFilterName = pFilter->GetName(); 309 } 310 } 311 } 312 else 313 { 314 //Test to see if this begins with xml and if so run it through 315 //the MathML filter. There are all sorts of things wrong with 316 //this approach, to be fixed at a better level than here 317 SvStream *pStrm = aMedium.GetInStream(); 318 aTypeName.Erase(); 319 if (pStrm && !pStrm->GetError()) 320 { 321 SotStorageRef aStorage = new SotStorage ( pStrm, sal_False ); 322 if ( !aStorage->GetError() ) 323 { 324 if ( aStorage->IsStream( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "Equation Native" ) ) ) ) 325 { 326 sal_uInt8 nVersion; 327 if (GetMathTypeVersion( aStorage, nVersion ) && nVersion <=3) 328 aTypeName.AssignAscii( "math_MathType_3x" ); 329 } 330 } 331 else 332 { 333 const sal_uInt16 nSize = 5; 334 sal_Char aBuffer[nSize+1]; 335 aBuffer[nSize] = 0; 336 pStrm->Seek( STREAM_SEEK_TO_BEGIN ); 337 sal_uLong nBytesRead = pStrm->Read( aBuffer, nSize ); 338 if (nBytesRead == nSize) 339 { 340 if (0 == strncmp( "<?xml",aBuffer,nSize)) 341 { 342 static const sal_Char sFltrNm_2[] = MATHML_XML; 343 static const sal_Char sTypeNm_2[] = "math_MathML_XML_Math"; 344 aFilterName.AssignAscii( sFltrNm_2 ); 345 aTypeName.AssignAscii( sTypeNm_2 ); 346 } 347 } 348 } 349 350 if ( aTypeName.Len() ) 351 { 352 const SfxFilter* pFilt = SfxFilterMatcher( String::CreateFromAscii("smath") ).GetFilter4EA( aTypeName ); 353 if ( pFilt ) 354 aFilterName = pFilt->GetName(); 355 } 356 } 357 } 358 } 359 } 360 361 if ( nIndexOfInputStream == -1 && xStream.is() ) 362 { 363 // if input stream wasn't part of the descriptor, now it should be, otherwise the content would be opend twice 364 lDescriptor.realloc( nPropertyCount + 1 ); 365 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("InputStream"); 366 lDescriptor[nPropertyCount].Value <<= xStream; 367 nPropertyCount++; 368 } 369 370 if ( nIndexOfContent == -1 && xContent.is() ) 371 { 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("UCBContent"); 375 lDescriptor[nPropertyCount].Value <<= xContent; 376 nPropertyCount++; 377 } 378 379 if ( bReadOnly != bWasReadOnly ) 380 { 381 if ( nIndexOfReadOnlyFlag == -1 ) 382 { 383 lDescriptor.realloc( nPropertyCount + 1 ); 384 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("ReadOnly"); 385 lDescriptor[nPropertyCount].Value <<= bReadOnly; 386 nPropertyCount++; 387 } 388 else 389 lDescriptor[nIndexOfReadOnlyFlag].Value <<= bReadOnly; 390 } 391 392 if ( !bRepairPackage && bRepairAllowed ) 393 { 394 lDescriptor.realloc( nPropertyCount + 1 ); 395 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("RepairPackage"); 396 lDescriptor[nPropertyCount].Value <<= bRepairAllowed; 397 nPropertyCount++; 398 399 bOpenAsTemplate = sal_True; 400 401 // TODO/LATER: set progress bar that should be used 402 } 403 404 if ( bOpenAsTemplate ) 405 { 406 if ( nIndexOfTemplateFlag == -1 ) 407 { 408 lDescriptor.realloc( nPropertyCount + 1 ); 409 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("AsTemplate"); 410 lDescriptor[nPropertyCount].Value <<= bOpenAsTemplate; 411 nPropertyCount++; 412 } 413 else 414 lDescriptor[nIndexOfTemplateFlag].Value <<= bOpenAsTemplate; 415 } 416 417 if ( aDocumentTitle.getLength() ) 418 { 419 // the title was set here 420 if ( nIndexOfDocumentTitle == -1 ) 421 { 422 lDescriptor.realloc( nPropertyCount + 1 ); 423 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("DocumentTitle"); 424 lDescriptor[nPropertyCount].Value <<= aDocumentTitle; 425 nPropertyCount++; 426 } 427 else 428 lDescriptor[nIndexOfDocumentTitle].Value <<= aDocumentTitle; 429 } 430 431 if ( !aFilterName.Len() ) 432 aTypeName.Erase(); 433 434 return aTypeName; 435 } 436 437 SFX_IMPL_SINGLEFACTORY( SmFilterDetect ) 438 439 /* XServiceInfo */ 440 UNOOUSTRING SAL_CALL SmFilterDetect::getImplementationName() throw( UNORUNTIMEEXCEPTION ) 441 { 442 return impl_getStaticImplementationName(); 443 } 444 \ 445 /* XServiceInfo */ 446 sal_Bool SAL_CALL SmFilterDetect::supportsService( const UNOOUSTRING& sServiceName ) throw( UNORUNTIMEEXCEPTION ) 447 { 448 UNOSEQUENCE< UNOOUSTRING > seqServiceNames = getSupportedServiceNames(); 449 const UNOOUSTRING* pArray = seqServiceNames.getConstArray(); 450 for ( sal_Int32 nCounter=0; nCounter<seqServiceNames.getLength(); nCounter++ ) 451 { 452 if ( pArray[nCounter] == sServiceName ) 453 { 454 return sal_True ; 455 } 456 } 457 return sal_False ; 458 } 459 460 /* XServiceInfo */ 461 UNOSEQUENCE< UNOOUSTRING > SAL_CALL SmFilterDetect::getSupportedServiceNames() throw( UNORUNTIMEEXCEPTION ) 462 { 463 return impl_getStaticSupportedServiceNames(); 464 } 465 466 /* Helper for XServiceInfo */ 467 UNOSEQUENCE< UNOOUSTRING > SmFilterDetect::impl_getStaticSupportedServiceNames() 468 { 469 UNOMUTEXGUARD aGuard( UNOMUTEX::getGlobalMutex() ); 470 UNOSEQUENCE< UNOOUSTRING > seqServiceNames( 1 ); 471 seqServiceNames.getArray() [0] = UNOOUSTRING::createFromAscii( "com.sun.star.frame.ExtendedTypeDetection" ); 472 return seqServiceNames ; 473 } 474 475 /* Helper for XServiceInfo */ 476 UNOOUSTRING SmFilterDetect::impl_getStaticImplementationName() 477 { 478 return UNOOUSTRING::createFromAscii( "com.sun.star.comp.math.FormatDetector" ); 479 } 480 481 /* Helper for registry */ 482 UNOREFERENCE< UNOXINTERFACE > SAL_CALL SmFilterDetect::impl_createInstance( const UNOREFERENCE< UNOXMULTISERVICEFACTORY >& xServiceManager ) throw( UNOEXCEPTION ) 483 { 484 return UNOREFERENCE< UNOXINTERFACE >( *new SmFilterDetect( xServiceManager ) ); 485 } 486 487