LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/sc/source/ui/unoobj - scdetect.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 100 317 31.5 %
Date: 2013-07-09 Functions: 9 15 60.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10