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_sc.hxx" 30 31 #include "scdetect.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/container/XNameAccess.hpp> 45 #include <com/sun/star/io/XInputStream.hpp> 46 #include <com/sun/star/task/XInteractionHandler.hpp> 47 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> 48 #include <com/sun/star/ucb/CommandAbortedException.hpp> 49 #include <com/sun/star/ucb/InteractiveAppException.hpp> 50 #include <com/sun/star/ucb/XContent.hpp> 51 #include <com/sun/star/packages/zip/ZipIOException.hpp> 52 53 54 #include <framework/interaction.hxx> 55 56 #ifndef _TOOLKIT_UNOHLP_HXX 57 #include <toolkit/helper/vclunohelper.hxx> 58 #endif 59 #include <ucbhelper/simpleinteractionrequest.hxx> 60 61 #include <svtools/parhtml.hxx> 62 #include <rtl/ustring.h> 63 #include <rtl/logfile.hxx> 64 #include <svl/itemset.hxx> 65 #include <vcl/window.hxx> 66 #include <svl/eitem.hxx> 67 #include <svl/stritem.hxx> 68 #include <tools/urlobj.hxx> 69 #include <vos/mutex.hxx> 70 #include <svtools/sfxecode.hxx> 71 #include <svtools/ehdl.hxx> 72 #include <sot/storinfo.hxx> 73 #include <vcl/svapp.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/app.hxx> 80 #include <sfx2/brokenpackageint.hxx> 81 #include <sot/storage.hxx> 82 83 using namespace ::com::sun::star; 84 using namespace ::com::sun::star::uno; 85 using namespace ::com::sun::star::io; 86 using namespace ::com::sun::star::frame; 87 using namespace ::com::sun::star::task; 88 using namespace ::com::sun::star::beans; 89 using namespace ::com::sun::star::lang; 90 using namespace ::com::sun::star::ucb; 91 using ::rtl::OUString; 92 93 ScFilterDetect::ScFilterDetect( const REFERENCE < ::com::sun::star::lang::XMultiServiceFactory >& /* xFactory */ ) 94 { 95 } 96 97 ScFilterDetect::~ScFilterDetect() 98 { 99 } 100 101 static const sal_Char __FAR_DATA pFilterSc50[] = "StarCalc 5.0"; 102 static const sal_Char __FAR_DATA pFilterSc50Temp[] = "StarCalc 5.0 Vorlage/Template"; 103 static const sal_Char __FAR_DATA pFilterSc40[] = "StarCalc 4.0"; 104 static const sal_Char __FAR_DATA pFilterSc40Temp[] = "StarCalc 4.0 Vorlage/Template"; 105 static const sal_Char __FAR_DATA pFilterSc30[] = "StarCalc 3.0"; 106 static const sal_Char __FAR_DATA pFilterSc30Temp[] = "StarCalc 3.0 Vorlage/Template"; 107 static const sal_Char __FAR_DATA pFilterSc10[] = "StarCalc 1.0"; 108 static const sal_Char __FAR_DATA pFilterXML[] = "StarOffice XML (Calc)"; 109 static const sal_Char __FAR_DATA pFilterAscii[] = "Text - txt - csv (StarCalc)"; 110 static const sal_Char __FAR_DATA pFilterLotus[] = "Lotus"; 111 static const sal_Char __FAR_DATA pFilterQPro6[] = "Quattro Pro 6.0"; 112 static const sal_Char __FAR_DATA pFilterExcel4[] = "MS Excel 4.0"; 113 static const sal_Char __FAR_DATA pFilterEx4Temp[] = "MS Excel 4.0 Vorlage/Template"; 114 static const sal_Char __FAR_DATA pFilterExcel5[] = "MS Excel 5.0/95"; 115 static const sal_Char __FAR_DATA pFilterEx5Temp[] = "MS Excel 5.0/95 Vorlage/Template"; 116 static const sal_Char __FAR_DATA pFilterExcel95[] = "MS Excel 95"; 117 static const sal_Char __FAR_DATA pFilterEx95Temp[] = "MS Excel 95 Vorlage/Template"; 118 static const sal_Char __FAR_DATA pFilterExcel97[] = "MS Excel 97"; 119 static const sal_Char __FAR_DATA pFilterEx97Temp[] = "MS Excel 97 Vorlage/Template"; 120 static const sal_Char __FAR_DATA pFilterExcelXML[] = "MS Excel 2003 XML"; 121 static const sal_Char __FAR_DATA pFilterDBase[] = "dBase"; 122 static const sal_Char __FAR_DATA pFilterDif[] = "DIF"; 123 static const sal_Char __FAR_DATA pFilterSylk[] = "SYLK"; 124 static const sal_Char __FAR_DATA pFilterHtml[] = "HTML (StarCalc)"; 125 static const sal_Char __FAR_DATA pFilterHtmlWeb[] = "calc_HTML_WebQuery"; 126 static const sal_Char __FAR_DATA pFilterRtf[] = "Rich Text Format (StarCalc)"; 127 128 129 static sal_Bool lcl_MayBeAscii( SvStream& rStream ) 130 { 131 // ASCII/CSV is considered possible if there are no null bytes, or a Byte 132 // Order Mark is present, or if, for Unicode UCS2/UTF-16, all null bytes 133 // are on either even or uneven byte positions. 134 135 rStream.Seek(STREAM_SEEK_TO_BEGIN); 136 137 const size_t nBufSize = 2048; 138 sal_uInt16 aBuffer[ nBufSize ]; 139 sal_uInt8* pByte = reinterpret_cast<sal_uInt8*>(aBuffer); 140 sal_uLong nBytesRead = rStream.Read( pByte, nBufSize*2); 141 142 if ( nBytesRead >= 2 && (aBuffer[0] == 0xfffe || aBuffer[0] == 0xfeff) ) 143 { 144 // Unicode BOM file may contain null bytes. 145 return sal_True; 146 } 147 148 const sal_uInt16* p = aBuffer; 149 sal_uInt16 nMask = 0xffff; 150 nBytesRead /= 2; 151 while( nBytesRead-- && nMask ) 152 { 153 sal_uInt16 nVal = *p++ & nMask; 154 if (!(nVal & 0x00ff)) 155 nMask &= 0xff00; 156 if (!(nVal & 0xff00)) 157 nMask &= 0x00ff; 158 } 159 160 return nMask != 0; 161 } 162 163 static const SfxFilter* lcl_DetectExcelXML( SvStream& rStream, SfxFilterMatcher& rMatcher ) 164 { 165 const SfxFilter* pFound = NULL; 166 rStream.Seek(STREAM_SEEK_TO_BEGIN); 167 168 const size_t nBufSize = 4000; 169 sal_uInt8 aBuffer[ nBufSize ]; 170 sal_uLong nBytesRead = rStream.Read( aBuffer, nBufSize ); 171 sal_uLong nXMLStart = 0; 172 173 // Skip UTF-8 BOM if present. 174 // No need to handle UTF-16 etc (also rejected in XMLFilterDetect). 175 if ( nBytesRead >= 3 && aBuffer[0] == 0xEF && aBuffer[1] == 0xBB && aBuffer[2] == 0xBF ) 176 nXMLStart = 3; 177 178 if ( nBytesRead >= nXMLStart + 5 && rtl_compareMemory( aBuffer+nXMLStart, "<?xml", 5 ) == 0 ) 179 { 180 // Be consistent with XMLFilterDetect service: Check for presence of "Workbook" in XML file. 181 182 rtl::OString aTryStr( "Workbook" ); 183 rtl::OString aFileString(reinterpret_cast<const sal_Char*>(aBuffer), nBytesRead); 184 185 if (aFileString.indexOf(aTryStr) >= 0) 186 pFound = rMatcher.GetFilter4FilterName( String::CreateFromAscii(pFilterExcelXML) ); 187 } 188 189 return pFound; 190 } 191 192 static sal_Bool lcl_MayBeDBase( SvStream& rStream ) 193 { 194 // Look for dbf marker, see connectivity/source/inc/dbase/DTable.hxx 195 // DBFType for values. 196 const sal_uInt8 nValidMarks[] = { 197 0x03, 0x04, 0x05, 0x30, 0x43, 0xB3, 0x83, 0x8b, 0x8e, 0xf5 }; 198 sal_uInt8 nMark; 199 rStream.Seek(STREAM_SEEK_TO_BEGIN); 200 rStream >> nMark; 201 bool bValidMark = false; 202 for (size_t i=0; i < sizeof(nValidMarks)/sizeof(nValidMarks[0]) && !bValidMark; ++i) 203 { 204 if (nValidMarks[i] == nMark) 205 bValidMark = true; 206 } 207 if ( !bValidMark ) 208 return sal_False; 209 210 const size_t nHeaderBlockSize = 32; 211 // Empty dbf is >= 32*2+1 bytes in size. 212 const size_t nEmptyDbf = nHeaderBlockSize * 2 + 1; 213 214 rStream.Seek(STREAM_SEEK_TO_END); 215 sal_uLong nSize = rStream.Tell(); 216 if ( nSize < nEmptyDbf ) 217 return sal_False; 218 219 // length of header starts at 8 220 rStream.Seek(8); 221 sal_uInt16 nHeaderLen; 222 rStream >> nHeaderLen; 223 224 if ( nHeaderLen < nEmptyDbf || nSize < nHeaderLen ) 225 return sal_False; 226 227 // Last byte of header must be 0x0d, this is how it's specified. 228 // #i9581#,#i26407# but some applications don't follow the specification 229 // and pad the header with one byte 0x00 to reach an 230 // even boundary. Some (#i88577# ) even pad more or pad using a 0x1a ^Z 231 // control character (#i8857#). This results in: 232 // Last byte of header must be 0x0d on 32 bytes boundary. 233 sal_uInt16 nBlocks = (nHeaderLen - 1) / nHeaderBlockSize; 234 sal_uInt8 nEndFlag = 0; 235 while ( nBlocks > 1 && nEndFlag != 0x0d ) { 236 rStream.Seek( nBlocks-- * nHeaderBlockSize ); 237 rStream >> nEndFlag; 238 } 239 240 return ( 0x0d == nEndFlag ); 241 } 242 243 #if 0 244 static sal_Bool lcl_IsAnyXMLFilter( const SfxFilter* pFilter ) 245 { 246 if ( !pFilter ) 247 return sal_False; 248 249 // sal_True for XML file or template 250 // (template filter has no internal name -> allow configuration key names) 251 252 String aName(pFilter->GetFilterName()); 253 return aName.EqualsAscii(pFilterXML) || 254 aName.EqualsAscii("calc_StarOffice_XML_Calc") || 255 aName.EqualsAscii("calc_StarOffice_XML_Calc_Template"); 256 } 257 #endif 258 259 ::rtl::OUString SAL_CALL ScFilterDetect::detect( ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& lDescriptor ) throw( ::com::sun::star::uno::RuntimeException ) 260 { 261 REFERENCE< XInputStream > xStream; 262 REFERENCE< XContent > xContent; 263 REFERENCE< XInteractionHandler > xInteraction; 264 String aURL; 265 ::rtl::OUString sTemp; 266 String aTypeName; // a name describing the type (from MediaDescriptor, usually from flat detection) 267 String aPreselectedFilterName; // a name describing the filter to use (from MediaDescriptor, usually from UI action) 268 269 ::rtl::OUString aDocumentTitle; // interesting only if set in this method 270 271 // opening as template is done when a parameter tells to do so and a template filter can be detected 272 // (otherwise no valid filter would be found) or if the detected filter is a template filter and 273 // there is no parameter that forbids to open as template 274 sal_Bool bOpenAsTemplate = sal_False; 275 sal_Bool bWasReadOnly = sal_False, bReadOnly = sal_False; 276 277 sal_Bool bRepairPackage = sal_False; 278 sal_Bool bRepairAllowed = sal_False; 279 280 // now some parameters that can already be in the array, but may be overwritten or new inserted here 281 // remember their indices in the case new values must be added to the array 282 sal_Int32 nPropertyCount = lDescriptor.getLength(); 283 sal_Int32 nIndexOfFilterName = -1; 284 sal_Int32 nIndexOfInputStream = -1; 285 sal_Int32 nIndexOfContent = -1; 286 sal_Int32 nIndexOfReadOnlyFlag = -1; 287 sal_Int32 nIndexOfTemplateFlag = -1; 288 sal_Int32 nIndexOfDocumentTitle = -1; 289 bool bFakeXLS = false; 290 291 for( sal_Int32 nProperty=0; nProperty<nPropertyCount; ++nProperty ) 292 { 293 // extract properties 294 if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("URL")) ) 295 { 296 lDescriptor[nProperty].Value >>= sTemp; 297 aURL = sTemp; 298 } 299 else if( !aURL.Len() && lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("FileName")) ) 300 { 301 lDescriptor[nProperty].Value >>= sTemp; 302 aURL = sTemp; 303 } 304 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("TypeName")) ) 305 { 306 lDescriptor[nProperty].Value >>= sTemp; 307 aTypeName = sTemp; 308 } 309 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("FilterName")) ) 310 { 311 lDescriptor[nProperty].Value >>= sTemp; 312 aPreselectedFilterName = sTemp; 313 314 // if the preselected filter name is not correct, it must be erased after detection 315 // remember index of property to get access to it later 316 nIndexOfFilterName = nProperty; 317 } 318 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("InputStream")) ) 319 nIndexOfInputStream = nProperty; 320 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("ReadOnly")) ) 321 nIndexOfReadOnlyFlag = nProperty; 322 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("UCBContent")) ) 323 nIndexOfContent = nProperty; 324 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("AsTemplate")) ) 325 { 326 lDescriptor[nProperty].Value >>= bOpenAsTemplate; 327 nIndexOfTemplateFlag = nProperty; 328 } 329 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("InteractionHandler")) ) 330 lDescriptor[nProperty].Value >>= xInteraction; 331 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("RepairPackage")) ) 332 lDescriptor[nProperty].Value >>= bRepairPackage; 333 else if( lDescriptor[nProperty].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("DocumentTitle")) ) 334 nIndexOfDocumentTitle = nProperty; 335 } 336 337 // can't check the type for external filters, so set the "dont" flag accordingly 338 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 339 //SfxFilterFlags nMust = SFX_FILTER_IMPORT, nDont = SFX_FILTER_NOTINSTALLED; 340 341 SfxAllItemSet *pSet = new SfxAllItemSet( SFX_APP()->GetPool() ); 342 TransformParameters( SID_OPENDOC, lDescriptor, *pSet ); 343 SFX_ITEMSET_ARG( pSet, pItem, SfxBoolItem, SID_DOC_READONLY, sal_False ); 344 345 bWasReadOnly = pItem && pItem->GetValue(); 346 347 const SfxFilter* pFilter = 0; 348 String aPrefix = String::CreateFromAscii( "private:factory/" ); 349 if( aURL.Match( aPrefix ) == aPrefix.Len() ) 350 { 351 String aPattern( aPrefix ); 352 aPattern += String::CreateFromAscii("scalc"); 353 if ( aURL.Match( aPattern ) >= aPattern.Len() ) 354 pFilter = SfxFilter::GetDefaultFilterFromFactory( aURL ); 355 } 356 else 357 { 358 // container for Calc filters 359 SfxFilterMatcher aMatcher( String::CreateFromAscii("scalc") ); 360 if ( aPreselectedFilterName.Len() ) 361 pFilter = SfxFilter::GetFilterByName( aPreselectedFilterName ); 362 else if( aTypeName.Len() ) 363 pFilter = aMatcher.GetFilter4EA( aTypeName ); 364 365 // ctor of SfxMedium uses owner transition of ItemSet 366 SfxMedium aMedium( aURL, bWasReadOnly ? STREAM_STD_READ : STREAM_STD_READWRITE, sal_False, NULL, pSet ); 367 aMedium.UseInteractionHandler( sal_True ); 368 369 sal_Bool bIsStorage = aMedium.IsStorage(); 370 if ( aMedium.GetErrorCode() == ERRCODE_NONE ) 371 { 372 // remember input stream and content and put them into the descriptor later 373 // should be done here since later the medium can switch to a version 374 xStream.set(aMedium.GetInputStream()); 375 xContent.set(aMedium.GetContent()); 376 bReadOnly = aMedium.IsReadOnly(); 377 378 // maybe that IsStorage() already created an error! 379 if ( bIsStorage ) 380 { 381 uno::Reference < embed::XStorage > xStorage(aMedium.GetStorage( sal_False )); 382 if ( aMedium.GetLastStorageCreationState() != ERRCODE_NONE ) 383 { 384 // error during storage creation means _here_ that the medium 385 // is broken, but we can not handle it in medium since unpossibility 386 // to create a storage does not _always_ means that the medium is broken 387 aMedium.SetError( aMedium.GetLastStorageCreationState(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); 388 if ( xInteraction.is() ) 389 { 390 OUString empty; 391 try 392 { 393 InteractiveAppException xException( empty, 394 REFERENCE< XInterface >(), 395 InteractionClassification_ERROR, 396 aMedium.GetError() ); 397 398 REFERENCE< XInteractionRequest > xRequest( 399 new ucbhelper::SimpleInteractionRequest( makeAny( xException ), 400 ucbhelper::CONTINUATION_APPROVE ) ); 401 xInteraction->handle( xRequest ); 402 } 403 catch ( Exception & ) {}; 404 } 405 } 406 else if ( xStorage.is() ) 407 { 408 try 409 { 410 String aFilterName; 411 if ( pFilter ) 412 aFilterName = pFilter->GetName(); 413 aTypeName = SfxFilter::GetTypeFromStorage( xStorage, pFilter ? pFilter->IsOwnTemplateFormat() : sal_False, &aFilterName ); 414 } 415 catch( lang::WrappedTargetException& aWrap ) 416 { 417 packages::zip::ZipIOException aZipException; 418 419 // repairing is done only if this type is requested from outside 420 if ( ( aWrap.TargetException >>= aZipException ) && aTypeName.Len() ) 421 { 422 if ( xInteraction.is() ) 423 { 424 // the package is broken one 425 aDocumentTitle = aMedium.GetURLObject().getName( 426 INetURLObject::LAST_SEGMENT, 427 true, 428 INetURLObject::DECODE_WITH_CHARSET ); 429 430 if ( !bRepairPackage ) 431 { 432 // ask the user whether he wants to try to repair 433 RequestPackageReparation aRequest( aDocumentTitle ); 434 xInteraction->handle( aRequest.GetRequest() ); 435 bRepairAllowed = aRequest.isApproved(); 436 } 437 438 if ( !bRepairAllowed ) 439 { 440 // repair either not allowed or not successful 441 NotifyBrokenPackage aNotifyRequest( aDocumentTitle ); 442 xInteraction->handle( aNotifyRequest.GetRequest() ); 443 } 444 } 445 446 if ( !bRepairAllowed ) 447 aTypeName.Erase(); 448 } 449 } 450 catch( uno::RuntimeException& ) 451 { 452 throw; 453 } 454 catch( uno::Exception& ) 455 { 456 aTypeName.Erase(); 457 } 458 459 if ( aTypeName.Len() ) 460 pFilter = SfxFilterMatcher( String::CreateFromAscii("scalc") ).GetFilter4EA( aTypeName ); 461 462 } 463 } 464 else 465 { 466 bool bIsXLS = false; 467 SvStream* pStream = aMedium.GetInStream(); 468 const SfxFilter* pPreselectedFilter = pFilter; 469 if ( pPreselectedFilter && pPreselectedFilter->GetName().SearchAscii("Excel") != STRING_NOTFOUND ) 470 bIsXLS = true; 471 pFilter = 0; 472 if ( pStream ) 473 { 474 SotStorageRef aStorage = new SotStorage ( pStream, sal_False ); 475 if ( !aStorage->GetError() ) 476 { 477 // Excel-5: detect through contained streams 478 // there are some "excel" formats from 3rd party vendors that need to be distinguished 479 String aStreamName(RTL_CONSTASCII_STRINGPARAM("Workbook")); 480 sal_Bool bExcel97Stream = ( aStorage->IsStream( aStreamName ) ); 481 482 aStreamName = String(RTL_CONSTASCII_STRINGPARAM("Book")); 483 sal_Bool bExcel5Stream = ( aStorage->IsStream( aStreamName ) ); 484 if ( bExcel97Stream || bExcel5Stream ) 485 { 486 if ( bExcel97Stream ) 487 { 488 String aOldName; 489 sal_Bool bIsCalcFilter = sal_True; 490 if ( pPreselectedFilter ) 491 { 492 // cross filter; now this should be a type detection only, not a filter detection 493 // we can simulate it by preserving the preselected filter if the type matches 494 // example: Excel filters for Writer 495 aOldName = pPreselectedFilter->GetFilterName(); 496 bIsCalcFilter = pPreselectedFilter->GetServiceName().EqualsAscii("com.sun.star.sheet.SpreadsheetDocument"); 497 } 498 499 if ( aOldName.EqualsAscii(pFilterEx97Temp) || !bIsCalcFilter ) 500 { 501 // Excel 97 template selected -> keep selection 502 } 503 else if ( bExcel5Stream && 504 ( aOldName.EqualsAscii(pFilterExcel5) || aOldName.EqualsAscii(pFilterEx5Temp) || 505 aOldName.EqualsAscii(pFilterExcel95) || aOldName.EqualsAscii(pFilterEx95Temp) ) ) 506 { 507 // dual format file and Excel 5 selected -> keep selection 508 } 509 else 510 { 511 // else use Excel 97 filter 512 pFilter = aMatcher.GetFilter4FilterName( String::CreateFromAscii(pFilterExcel97) ); 513 } 514 } 515 else if ( bExcel5Stream ) 516 { 517 String aOldName; 518 sal_Bool bIsCalcFilter = sal_True; 519 if ( pPreselectedFilter ) 520 { 521 // cross filter; now this should be a type detection only, not a filter detection 522 // we can simulate it by preserving the preselected filter if the type matches 523 // example: Excel filters for Writer 524 aOldName = pPreselectedFilter->GetFilterName(); 525 bIsCalcFilter = pPreselectedFilter->GetServiceName().EqualsAscii("com.sun.star.sheet.SpreadsheetDocument"); 526 } 527 528 if ( aOldName.EqualsAscii(pFilterExcel95) || aOldName.EqualsAscii(pFilterEx95Temp) || 529 aOldName.EqualsAscii(pFilterEx5Temp) || !bIsCalcFilter ) 530 { 531 // Excel 95 oder Vorlage (5 oder 95) eingestellt -> auch gut 532 } 533 else if ( aOldName.EqualsAscii(pFilterEx97Temp) ) 534 { 535 // #101923# auto detection has found template -> return Excel5 template 536 pFilter = aMatcher.GetFilter4FilterName( String::CreateFromAscii(pFilterEx5Temp) ); 537 } 538 else 539 { 540 // sonst wird als Excel 5-Datei erkannt 541 pFilter = aMatcher.GetFilter4FilterName( String::CreateFromAscii(pFilterExcel5) ); 542 } 543 } 544 } 545 } 546 else 547 { 548 SvStream &rStr = *pStream; 549 550 // Tabelle mit Suchmustern 551 // Bedeutung der Sequenzen 552 // 0x00??: genau Byte 0x?? muss an dieser Stelle stehen 553 // 0x0100: ein Byte ueberlesen (don't care) 554 // 0x02nn: ein Byte aus 0xnn Alternativen folgt 555 // 0x8000: Erkennung abgeschlossen 556 // 557 558 #define M_DC 0x0100 559 #define M_ALT(ANZ) (0x0200+(ANZ)) 560 #define M_ENDE 0x8000 561 562 static const sal_uInt16 pLotus[] = // Lotus 1/1A/2 563 { 0x0000, 0x0000, 0x0002, 0x0000, 564 M_ALT(2), 0x0004, 0x0006, 565 0x0004, M_ENDE }; 566 567 static const sal_uInt16 pLotusNew[] = // Lotus >= 9.7 568 { 0x0000, 0x0000, M_DC, 0x0000, // Rec# + Len (0x1a) 569 M_ALT(3), 0x0003, 0x0004, 0x0005, // File Revision Code 97->ME 570 0x0010, 0x0004, 0x0000, 0x0000, 571 M_ENDE }; 572 573 static const sal_uInt16 pExcel1[] = // Excel BIFF2, BIFF3, BIFF4 574 { 0x09, // lobyte of BOF rec ID (0x0009, 0x0209, 0x0409) 575 M_ALT(3), 0x00, 0x02, 0x04, // hibyte of BOF rec ID (0x0009, 0x0209, 0x0409) 576 M_ALT(3), 4, 6, 8, // lobyte of BOF rec size (4, 6, 8, 16) 577 0x00, // hibyte of BOF rec size (4, 6, 8, 16) 578 M_DC, M_DC, // any version 579 M_ALT(3), 0x10, 0x20, 0x40, // lobyte of data type (0x0010, 0x0020, 0x0040) 580 0x00, // hibyte of data type (0x0010, 0x0020, 0x0040) 581 M_ENDE }; 582 583 static const sal_uInt16 pExcel2[] = // Excel BIFF4 Workspace 584 { 0x09, // lobyte of BOF rec ID (0x0409) 585 0x04, // hibyte of BOF rec ID (0x0409) 586 M_ALT(3), 4, 6, 8, // lobyte of BOF rec size (4, 6, 8, 16) 587 0x00, // hibyte of BOF rec size (4, 6, 8, 16) 588 M_DC, M_DC, // any version 589 0x00, // lobyte of data type (0x0100) 590 0x01, // hibyte of data type (0x0100) 591 M_ENDE }; 592 593 static const sal_uInt16 pExcel3[] = // #i23425# Excel BIFF5, BIFF7, BIFF8 (simple book stream) 594 { 0x09, // lobyte of BOF rec ID (0x0809) 595 0x08, // hibyte of BOF rec ID (0x0809) 596 M_ALT(4), 4, 6, 8, 16, // lobyte of BOF rec size 597 0x00, // hibyte of BOF rec size 598 M_DC, M_DC, // any version 599 M_ALT(5), 0x05, 0x06, 0x10, 0x20, 0x40, // lobyte of data type 600 0x00, // hibyte of data type 601 M_ENDE }; 602 603 static const sal_uInt16 pSc10[] = // StarCalc 1.0 Dokumente 604 { 'B', 'l', 'a', 'i', 's', 'e', '-', 'T', 'a', 'b', 'e', 'l', 'l', 605 'e', 0x000A, 0x000D, 0x0000, // Sc10CopyRight[16] 606 M_DC, M_DC, M_DC, M_DC, M_DC, M_DC, M_DC, M_DC, M_DC, M_DC, M_DC, 607 M_DC, M_DC, // Sc10CopyRight[29] 608 M_ALT(2), 0x0065, 0x0066, // Versionsnummer 101 oder 102 609 0x0000, 610 M_ENDE }; 611 612 static const sal_uInt16 pLotus2[] = // Lotus >3 613 { 0x0000, 0x0000, 0x001A, 0x0000, // Rec# + Len (26) 614 M_ALT(2), 0x0000, 0x0002, // File Revision Code 615 0x0010, 616 0x0004, 0x0000, // File Revision Subcode 617 M_ENDE }; 618 619 static const sal_uInt16 pQPro[] = 620 { 0x0000, 0x0000, 0x0002, 0x0000, 621 M_ALT(4), 0x0001, 0x0002, // WB1, WB2 622 0x0006, 0x0007, // QPro 6/7 (?) 623 0x0010, 624 M_ENDE }; 625 626 static const sal_uInt16 pDIF1[] = // DIF mit CR-LF 627 { 628 'T', 'A', 'B', 'L', 'E', 629 M_DC, M_DC, 630 '0', ',', '1', 631 M_DC, M_DC, 632 '\"', 633 M_ENDE }; 634 635 static const sal_uInt16 pDIF2[] = // DIF mit CR oder LF 636 { 637 'T', 'A', 'B', 'L', 'E', 638 M_DC, 639 '0', ',', '1', 640 M_DC, 641 '\"', 642 M_ENDE }; 643 644 static const sal_uInt16 pSylk[] = // Sylk 645 { 646 'I', 'D', ';', 647 M_ALT(3), 'P', 'N', 'E', // 'P' plus undocumented Excel extensions 'N' and 'E' 648 M_ENDE }; 649 650 static const sal_uInt16 *ppFilterPatterns[] = // Arrays mit Suchmustern 651 { 652 pLotus, 653 pExcel1, 654 pExcel2, 655 pExcel3, 656 pSc10, 657 pDIF1, 658 pDIF2, 659 pSylk, 660 pLotusNew, 661 pLotus2, 662 pQPro 663 }; 664 const sal_uInt16 nFilterCount = sizeof(ppFilterPatterns) / sizeof(ppFilterPatterns[0]); 665 666 static const sal_Char* const pFilterName[] = // zugehoerige Filter 667 { 668 pFilterLotus, 669 pFilterExcel4, 670 pFilterExcel4, 671 pFilterExcel4, 672 pFilterSc10, 673 pFilterDif, 674 pFilterDif, 675 pFilterSylk, 676 pFilterLotus, 677 pFilterLotus, 678 pFilterQPro6 679 }; 680 681 // const sal_uInt16 nByteMask = 0xFF; 682 683 // suchen Sie jetzt! 684 // ... realisiert ueber 'Mustererkennung' 685 686 sal_uInt8 nAkt; 687 sal_Bool bSync; // Datei und Muster stimmen ueberein 688 sal_uInt16 nFilter; // Zaehler ueber alle Filter 689 const sal_uInt16 *pSearch; // aktuelles Musterwort 690 691 for ( nFilter = 0 ; nFilter < nFilterCount ; nFilter++ ) 692 { 693 rStr.Seek( 0 ); // am Anfang war alles Uebel... 694 rStr >> nAkt; 695 pSearch = ppFilterPatterns[ nFilter ]; 696 bSync = sal_True; 697 while( !rStr.IsEof() && bSync ) 698 { 699 register sal_uInt16 nMuster = *pSearch; 700 701 if( nMuster < 0x0100 ) 702 { // direkter Byte-Vergleich 703 if( ( sal_uInt8 ) nMuster != nAkt ) 704 bSync = sal_False; 705 } 706 else if( nMuster & M_DC ) 707 { // don't care 708 } 709 else if( nMuster & M_ALT(0) ) 710 { // alternative Bytes 711 sal_uInt8 nAnzAlt = ( sal_uInt8 ) nMuster; 712 bSync = sal_False; // zunaechst unsynchron 713 while( nAnzAlt > 0 ) 714 { 715 pSearch++; 716 if( ( sal_uInt8 ) *pSearch == nAkt ) 717 bSync = sal_True; // jetzt erst Synchronisierung 718 nAnzAlt--; 719 } 720 } 721 else if( nMuster & M_ENDE ) 722 { // Format detected 723 if ( pFilterName[nFilter] == pFilterExcel4 && pPreselectedFilter && 724 ( (pPreselectedFilter)->GetFilterName().EqualsAscii(pFilterEx4Temp) || pPreselectedFilter->GetTypeName().EqualsAscii("calc_MS_Excel_40") ) ) 725 { 726 // Excel 4 erkannt, Excel 4 Vorlage eingestellt -> auch gut 727 // oder Excel 4 Filter anderer Applikation (simulated type detection!) 728 } 729 else 730 { // gefundenen Filter einstellen 731 pFilter = aMatcher.GetFilter4FilterName( String::CreateFromAscii(pFilterName[ nFilter ]) ); 732 } 733 bSync = sal_False; // leave inner loop 734 nFilter = nFilterCount; // leave outer loop 735 } 736 else 737 { // Tabellenfehler 738 DBG_ERROR( "-ScApplication::DetectFilter(): Fehler in Mustertabelle"); 739 } 740 741 pSearch++; 742 rStr >> nAkt; 743 } 744 } 745 746 if ( pPreselectedFilter && !pFilter ) 747 { 748 // further checks for filters only if they are preselected: ASCII, HTML, RTF, DBase 749 // without the preselection other filters (Writer) take precedence 750 // DBase can't be detected reliably, so it also needs preselection 751 bool bMaybeText = lcl_MayBeAscii( rStr ); 752 if ( pPreselectedFilter->GetFilterName().EqualsAscii(pFilterAscii) && bMaybeText ) 753 { 754 // Text filter is accepted if preselected 755 pFilter = pPreselectedFilter; 756 } 757 else 758 { 759 // get file header 760 rStr.Seek( 0 ); 761 const int nTrySize = 80; 762 ByteString aHeader; 763 for ( int j = 0; j < nTrySize && !rStr.IsEof(); j++ ) 764 { 765 sal_Char c; 766 rStr >> c; 767 aHeader += c; 768 } 769 aHeader += '\0'; 770 771 if ( HTMLParser::IsHTMLFormat( aHeader.GetBuffer() ) ) 772 { 773 // test for HTML 774 if ( pPreselectedFilter->GetName().EqualsAscii(pFilterHtml) ) 775 { 776 pFilter = pPreselectedFilter; 777 } 778 else 779 { 780 pFilter = aMatcher.GetFilter4FilterName( String::CreateFromAscii(pFilterHtmlWeb) ); 781 if ( bIsXLS ) 782 bFakeXLS = true; 783 } 784 } 785 else if ( bIsXLS && bMaybeText ) 786 { 787 // Detect Excel 2003 XML here only if XLS was preselected. 788 // The configured detection for Excel 2003 XML is still in XMLFilterDetect. 789 pFilter = lcl_DetectExcelXML( rStr, aMatcher ); 790 if (!pFilter) 791 pFilter = aMatcher.GetFilter4FilterName( String::CreateFromAscii(pFilterAscii) ); 792 bFakeXLS = true; 793 } 794 else if ( aHeader.CompareTo( "{\\rtf", 5 ) == COMPARE_EQUAL ) 795 { 796 // test for RTF 797 pFilter = aMatcher.GetFilter4FilterName( String::CreateFromAscii(pFilterRtf) ); 798 } 799 else if ( pPreselectedFilter->GetName().EqualsAscii(pFilterDBase) && lcl_MayBeDBase( rStr ) ) 800 pFilter = pPreselectedFilter; 801 } 802 } 803 } 804 } 805 } 806 } 807 } 808 809 if ( nIndexOfInputStream == -1 && xStream.is() ) 810 { 811 // if input stream wasn't part of the descriptor, now it should be, otherwise the content would be opend twice 812 lDescriptor.realloc( nPropertyCount + 1 ); 813 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("InputStream"); 814 lDescriptor[nPropertyCount].Value <<= xStream; 815 nPropertyCount++; 816 } 817 818 if ( nIndexOfContent == -1 && xContent.is() ) 819 { 820 // if input stream wasn't part of the descriptor, now it should be, otherwise the content would be opend twice 821 lDescriptor.realloc( nPropertyCount + 1 ); 822 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("UCBContent"); 823 lDescriptor[nPropertyCount].Value <<= xContent; 824 nPropertyCount++; 825 } 826 827 if ( bReadOnly != bWasReadOnly ) 828 { 829 if ( nIndexOfReadOnlyFlag == -1 ) 830 { 831 lDescriptor.realloc( nPropertyCount + 1 ); 832 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("ReadOnly"); 833 lDescriptor[nPropertyCount].Value <<= bReadOnly; 834 nPropertyCount++; 835 } 836 else 837 lDescriptor[nIndexOfReadOnlyFlag].Value <<= bReadOnly; 838 } 839 840 if ( !bRepairPackage && bRepairAllowed ) 841 { 842 lDescriptor.realloc( nPropertyCount + 1 ); 843 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("RepairPackage"); 844 lDescriptor[nPropertyCount].Value <<= bRepairAllowed; 845 nPropertyCount++; 846 847 bOpenAsTemplate = sal_True; 848 849 // TODO/LATER: set progress bar that should be used 850 } 851 852 if ( bOpenAsTemplate ) 853 { 854 if ( nIndexOfTemplateFlag == -1 ) 855 { 856 lDescriptor.realloc( nPropertyCount + 1 ); 857 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("AsTemplate"); 858 lDescriptor[nPropertyCount].Value <<= bOpenAsTemplate; 859 nPropertyCount++; 860 } 861 else 862 lDescriptor[nIndexOfTemplateFlag].Value <<= bOpenAsTemplate; 863 } 864 865 if ( aDocumentTitle.getLength() ) 866 { 867 // the title was set here 868 if ( nIndexOfDocumentTitle == -1 ) 869 { 870 lDescriptor.realloc( nPropertyCount + 1 ); 871 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("DocumentTitle"); 872 lDescriptor[nPropertyCount].Value <<= aDocumentTitle; 873 nPropertyCount++; 874 } 875 else 876 lDescriptor[nIndexOfDocumentTitle].Value <<= aDocumentTitle; 877 } 878 879 if ( bFakeXLS ) 880 { 881 if ( nIndexOfFilterName == -1 ) 882 { 883 lDescriptor.realloc( nPropertyCount + 1 ); 884 lDescriptor[nPropertyCount].Name = ::rtl::OUString::createFromAscii("FilterName"); 885 lDescriptor[nPropertyCount].Value <<= rtl::OUString(pFilter->GetName()); 886 nPropertyCount++; 887 } 888 else 889 lDescriptor[nIndexOfFilterName].Value <<= rtl::OUString(pFilter->GetName()); 890 } 891 892 if ( pFilter ) 893 aTypeName = pFilter->GetTypeName(); 894 else 895 aTypeName.Erase(); 896 return aTypeName; 897 } 898 899 SFX_IMPL_SINGLEFACTORY( ScFilterDetect ) 900 901 /* XServiceInfo */ 902 UNOOUSTRING SAL_CALL ScFilterDetect::getImplementationName() throw( UNORUNTIMEEXCEPTION ) 903 { 904 return impl_getStaticImplementationName(); 905 } 906 \ 907 /* XServiceInfo */ 908 sal_Bool SAL_CALL ScFilterDetect::supportsService( const UNOOUSTRING& sServiceName ) throw( UNORUNTIMEEXCEPTION ) 909 { 910 UNOSEQUENCE< UNOOUSTRING > seqServiceNames(getSupportedServiceNames()); 911 const UNOOUSTRING* pArray = seqServiceNames.getConstArray(); 912 for ( sal_Int32 nCounter=0; nCounter<seqServiceNames.getLength(); nCounter++ ) 913 { 914 if ( pArray[nCounter] == sServiceName ) 915 { 916 return sal_True ; 917 } 918 } 919 return sal_False ; 920 } 921 922 /* XServiceInfo */ 923 UNOSEQUENCE< UNOOUSTRING > SAL_CALL ScFilterDetect::getSupportedServiceNames() throw( UNORUNTIMEEXCEPTION ) 924 { 925 return impl_getStaticSupportedServiceNames(); 926 } 927 928 /* Helper for XServiceInfo */ 929 UNOSEQUENCE< UNOOUSTRING > ScFilterDetect::impl_getStaticSupportedServiceNames() 930 { 931 UNOMUTEXGUARD aGuard( UNOMUTEX::getGlobalMutex() ); 932 UNOSEQUENCE< UNOOUSTRING > seqServiceNames( 1 ); 933 seqServiceNames.getArray() [0] = UNOOUSTRING::createFromAscii( "com.sun.star.frame.ExtendedTypeDetection" ); 934 return seqServiceNames ; 935 } 936 937 /* Helper for XServiceInfo */ 938 UNOOUSTRING ScFilterDetect::impl_getStaticImplementationName() 939 { 940 return UNOOUSTRING::createFromAscii( "com.sun.star.comp.calc.FormatDetector" ); 941 } 942 943 /* Helper for registry */ 944 UNOREFERENCE< UNOXINTERFACE > SAL_CALL ScFilterDetect::impl_createInstance( const UNOREFERENCE< UNOXMULTISERVICEFACTORY >& xServiceManager ) throw( UNOEXCEPTION ) 945 { 946 return UNOREFERENCE< UNOXINTERFACE >( *new ScFilterDetect( xServiceManager ) ); 947 } 948 949