LCOV - code coverage report
Current view: top level - libreoffice/filter/source/config/cache - typedetection.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 227 468 48.5 %
Date: 2012-12-27 Functions: 22 26 84.6 %
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 "typedetection.hxx"
      21             : #include "constant.hxx"
      22             : 
      23             : #include <com/sun/star/document/XExtendedFilterDetection.hpp>
      24             : #include <com/sun/star/util/URLTransformer.hpp>
      25             : #include <com/sun/star/util/XURLTransformer.hpp>
      26             : 
      27             : #include <com/sun/star/io/XInputStream.hpp>
      28             : #include <com/sun/star/io/XSeekable.hpp>
      29             : #include <com/sun/star/task/XInteractionHandler.hpp>
      30             : #include <tools/wldcrd.hxx>
      31             : #include <rtl/ustrbuf.hxx>
      32             : #include <framework/interaction.hxx>
      33             : #include <tools/urlobj.hxx>
      34             : #include <unotools/localfilehelper.hxx>
      35             : #include <comphelper/processfactory.hxx>
      36             : 
      37             : 
      38             : namespace filter{
      39             :     namespace config{
      40             : 
      41        5546 : TypeDetection::TypeDetection(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
      42             : {
      43             :     BaseContainer::init(xSMGR                                         ,
      44             :                         TypeDetection::impl_getImplementationName()   ,
      45             :                         TypeDetection::impl_getSupportedServiceNames(),
      46        5546 :                         FilterCache::E_TYPE                           );
      47        5546 : }
      48             : 
      49             : 
      50             : 
      51       11092 : TypeDetection::~TypeDetection()
      52             : {
      53       11092 : }
      54             : 
      55             : 
      56             : 
      57        2597 : ::rtl::OUString SAL_CALL TypeDetection::queryTypeByURL(const ::rtl::OUString& sURL)
      58             :     throw (css::uno::RuntimeException)
      59             : {
      60        2597 :     ::rtl::OUString sType;
      61             : 
      62             :     // SAFE ->
      63        2597 :     ::osl::ResettableMutexGuard aLock(m_aLock);
      64             : 
      65        2597 :     css::util::URL  aURL;
      66        2597 :     aURL.Complete = sURL;
      67        2597 :     css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(comphelper::getComponentContext(m_xSMGR)));
      68        2597 :     xParser->parseStrict(aURL);
      69             : 
      70             :     // set std types as minimum requirement first!
      71             :     // Only in case no type was found for given URL,
      72             :     // use optional types too ...
      73        2597 :     FlatDetection lFlatTypes;
      74        2597 :     m_rCache->detectFlatForURL(aURL, lFlatTypes);
      75             : 
      76        5012 :     if (
      77        2597 :         (lFlatTypes.size() < 1                                ) &&
      78        2415 :         (!m_rCache->isFillState(FilterCache::E_CONTAINS_TYPES))
      79             :        )
      80             :     {
      81           0 :         m_rCache->load(FilterCache::E_CONTAINS_TYPES);
      82           0 :         m_rCache->detectFlatForURL(aURL, lFlatTypes);
      83             :     }
      84             : 
      85             :     // first item is guaranteed as "preferred" one!
      86        2597 :     if (lFlatTypes.size() > 0)
      87             :     {
      88         182 :         const FlatDetectionInfo& aMatch = *(lFlatTypes.begin());
      89         182 :         sType = aMatch.sType;
      90             :     }
      91             : 
      92        2597 :     return sType;
      93             :     // <- SAFE
      94             : }
      95             : 
      96             : namespace {
      97             : 
      98             : /**
      99             :  * Rank format types in order of complexity.  More complex formats are
     100             :  * ranked higher so that they get tested sooner over simpler formats.
     101             :  *
     102             :  * Guidelines to determine how complex a format is (subject to change):
     103             :  *
     104             :  * 1) compressed text (XML, HTML, etc)
     105             :  * 2) binary
     106             :  * 3) non-compressed text
     107             :  *   3.1) structured text
     108             :  *     3.1.1) dialect of a structured text (e.g. docbook XML)
     109             :  *     3.1.2) generic structured text (e.g. generic XML)
     110             :  *   3.2) non-structured text
     111             :  *
     112             :  * In each category, rank them from strictly-structured to
     113             :  * loosely-structured.
     114             :  */
     115         282 : int getFlatTypeRank(const rtl::OUString& rType)
     116             : {
     117             :     // List formats from more complex to less complex.
     118             :     // TODO: Add more.
     119             :     static const char* ranks[] = {
     120             :         // Compressed XML
     121             :         "writer8_template",
     122             :         "writer8",
     123             :         "calc8_template",
     124             :         "calc8",
     125             :         "writer_OOXML_Text_Template",
     126             :         "writer_OOXML",
     127             :         "writer_MS_Word_2007_Template",
     128             :         "writer_MS_Word_2007",
     129             :         "Office Open XML Spreadsheet Template",
     130             :         "Office Open XML Spreadsheet",
     131             :         "MS Excel 2007 XML Template",
     132             :         "MS Excel 2007 XML",
     133             : 
     134             :         // Compressed text
     135             :         "pdf_Portable_Document_Format",
     136             : 
     137             :         // Binary
     138             :         "writer_T602_Document",
     139             :         "writer_WordPerfect_Document",
     140             :         "writer_MS_Works_Document",
     141             :         "writer_MS_Word_97_Vorlage",
     142             :         "writer_MS_Word_97",
     143             :         "writer_MS_Word_95_Vorlage",
     144             :         "writer_MS_Word_95",
     145             :         "writer_MS_WinWord_60",
     146             :         "writer_MS_WinWord_5",
     147             :         "MS Excel 2007 Binary",
     148             :         "calc_MS_Excel_97_VorlageTemplate",
     149             :         "calc_MS_Excel_97",
     150             :         "calc_MS_Excel_95_VorlageTemplate",
     151             :         "calc_MS_Excel_95",
     152             :         "calc_MS_Excel_5095_VorlageTemplate",
     153             :         "calc_MS_Excel_5095",
     154             :         "calc_MS_Excel_40_VorlageTemplate",
     155             :         "calc_MS_Excel_40",
     156             :         "calc_Pocket_Excel_File",
     157             :         "calc_Lotus",
     158             :         "calc_QPro",
     159             :         "calc_SYLK",
     160             :         "calc_DIF",
     161             :         "calc_dBase",
     162             : 
     163             : 
     164             :         // Non-compressed XML
     165             :         "writer_ODT_FlatXML",
     166             :         "calc_ODS_FlatXML",
     167             :         "calc_MS_Excel_2003_XML",
     168             :         "writer_MS_Word_2003_XML",
     169             :         "writer_DocBook_File",
     170             :         "XHTML_File",
     171             : 
     172             :         // Non-compressed text
     173             :         "writer_Rich_Text_Format",
     174             :         "generic_HTML",
     175             :         "generic_Text"
     176             :     };
     177             : 
     178         282 :     size_t n = SAL_N_ELEMENTS(ranks);
     179             : 
     180        4028 :     for (size_t i = 0; i < n; ++i)
     181             :     {
     182        4028 :         if (rType.equalsAscii(ranks[i]))
     183         282 :             return n - i - 1;
     184             :     }
     185             : 
     186             :     // Not ranked.  Treat them equally.  Unranked formats have higher priority
     187             :     // than the ranked internal ones since they may be defined externally.
     188           0 :     return n;
     189             : }
     190             : 
     191             : /**
     192             :  * Types with matching pattern first, then extension, then custom ranks by
     193             :  * types, then types that are supported by the document service come next.
     194             :  * Lastly, sort them alphabetically.
     195             :  */
     196             : struct SortByPriority : public std::binary_function<FlatDetectionInfo, FlatDetectionInfo, bool>
     197             : {
     198         141 :     bool operator() (const FlatDetectionInfo& r1, const FlatDetectionInfo& r2) const
     199             :     {
     200         141 :         if (r1.bMatchByPattern != r2.bMatchByPattern)
     201           0 :             return r1.bMatchByPattern;
     202             : 
     203         141 :         if (r1.bMatchByExtension != r2.bMatchByExtension)
     204           0 :             return r1.bMatchByExtension;
     205             : 
     206         141 :         int rank1 = getFlatTypeRank(r1.sType);
     207         141 :         int rank2 = getFlatTypeRank(r2.sType);
     208             : 
     209         141 :         if (rank1 != rank2)
     210         141 :             return rank1 > rank2;
     211             : 
     212           0 :         if (r1.bPreselectedByDocumentService != r2.bPreselectedByDocumentService)
     213           0 :             return r1.bPreselectedByDocumentService;
     214             : 
     215             :         // All things being equal, sort them alphabetically.
     216           0 :         return r1.sType > r2.sType;
     217             :     }
     218             : };
     219             : 
     220             : struct EqualByName : public std::binary_function<FlatDetectionInfo, FlatDetectionInfo, bool>
     221             : {
     222         117 :     bool operator() (const FlatDetectionInfo& r1, const FlatDetectionInfo& r2) const
     223             :     {
     224         117 :         return r1.sType == r2.sType;
     225             :     }
     226             : };
     227             : 
     228             : }
     229             : 
     230         240 : ::rtl::OUString SAL_CALL TypeDetection::queryTypeByDescriptor(css::uno::Sequence< css::beans::PropertyValue >& lDescriptor,
     231             :                                                               sal_Bool                                         bAllowDeep )
     232             :     throw (css::uno::RuntimeException)
     233             : {
     234             :     // make the descriptor more useable :-)
     235         240 :     ::comphelper::MediaDescriptor stlDescriptor(lDescriptor);
     236             : 
     237             :     // SAFE -> ----------------------------------
     238         240 :     ::osl::ResettableMutexGuard aLock(m_aLock);
     239             : 
     240             :     //*******************************************
     241             :     // parse given URL to split it into e.g. main and jump marks ...
     242         240 :     ::rtl::OUString sURL = stlDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_URL(), ::rtl::OUString());
     243             : 
     244             : #if OSL_DEBUG_LEVEL > 0
     245             :     if (stlDescriptor.find(::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FileName" ))) != stlDescriptor.end())
     246             :         OSL_FAIL("Detect using of deprecated and already unsupported MediaDescriptor property \"FileName\"!");
     247             : #endif
     248             : 
     249         240 :     css::util::URL  aURL;
     250         240 :     aURL.Complete = sURL;
     251         240 :     css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(comphelper::getComponentContext(m_xSMGR)));
     252         240 :     xParser->parseStrict(aURL);
     253             : 
     254             :     rtl::OUString aSelectedFilter = stlDescriptor.getUnpackedValueOrDefault(
     255         240 :         comphelper::MediaDescriptor::PROP_FILTERNAME(), rtl::OUString());
     256         240 :     if (!aSelectedFilter.isEmpty())
     257             :     {
     258             :         // Caller specified the filter type.  Honor it.  Just get the default
     259             :         // type for that filter, and bail out.
     260           0 :         if (impl_validateAndSetFilterOnDescriptor(stlDescriptor, aSelectedFilter))
     261           0 :             return stlDescriptor[comphelper::MediaDescriptor::PROP_TYPENAME()].get<rtl::OUString>();
     262             :     }
     263             : 
     264             :     // preselected type or document service? use it as first "flat" detected
     265             :     // type later!
     266         240 :     FlatDetection lFlatTypes;
     267         240 :     impl_getPreselection(aURL, stlDescriptor, lFlatTypes);
     268             : 
     269             :     //*******************************************
     270             :     // get all types, which match to the given descriptor
     271             :     // That can be true by: extensions/url pattern/mime type etcpp.
     272         240 :     m_rCache->detectFlatForURL(aURL, lFlatTypes);
     273             : 
     274         240 :     aLock.clear();
     275             :     // <- SAFE ----------------------------------
     276             : 
     277             :     // Properly prioritize all candidate types.
     278         240 :     lFlatTypes.sort(SortByPriority());
     279         240 :     lFlatTypes.unique(EqualByName());
     280             : 
     281         240 :     ::rtl::OUString sType      ;
     282         240 :     ::rtl::OUString sLastChance;
     283             : 
     284             :     try
     285             :     {
     286             :         //*******************************************
     287             :         // verify every flat detected (or preselected!) type
     288             :         // by calling its registered deep detection service.
     289             :         // But break this loop if a type match to the given descriptor
     290             :         // by an URL pattern(!) or if deep detection isnt allowed from
     291             :         // outside (bAllowDeep=sal_False) or break the whole detection by
     292             :         // throwing an exception if creation of the might needed input
     293             :         // stream failed by e.g. an IO exception ...
     294         240 :         OUStringList lUsedDetectors;
     295         240 :         if (lFlatTypes.size()>0)
     296         182 :             sType = impl_detectTypeFlatAndDeep(stlDescriptor, lFlatTypes, bAllowDeep, lUsedDetectors, sLastChance);
     297             : 
     298             :         //*******************************************
     299             :         // if no flat detected (nor preselected!) type could be
     300             :         // verified and no error occurred during creation of
     301             :         // the might needed input stream, start detection
     302             :         // which uses all registered deep detection services.
     303         240 :         if (
     304         240 :             (sType.isEmpty()) &&
     305             :             (bAllowDeep        )
     306             :            )
     307             :         {
     308          58 :             sType = impl_detectTypeDeepOnly(stlDescriptor, lUsedDetectors);
     309             :         }
     310             : 
     311             :         //*******************************************
     312             :         // flat detection failed
     313             :         // pure deep detection failed
     314             :         // => ask might existing InteractionHandler
     315             :         // means: ask user for it's decision
     316         240 :         if (sType.isEmpty())
     317           3 :             sType = impl_askUserForTypeAndFilterIfAllowed(stlDescriptor);
     318             : 
     319             :         //*******************************************
     320             :         // no real detected type - but a might valid one.
     321             :         // update descriptor and set last chance for return.
     322         240 :         if (sType.isEmpty() && !sLastChance.isEmpty())
     323             :         {
     324             :             OSL_FAIL("set first flat detected type without a registered deep detection service as \"last chance\" ... nevertheless some other deep detections said \"NO\". I TRY IT!");
     325           0 :             sType = sLastChance;
     326         240 :         }
     327             :     }
     328           0 :     catch(const css::uno::RuntimeException&)
     329           0 :         { throw; }
     330           0 :     catch(const css::uno::Exception&)
     331           0 :         { sType = ::rtl::OUString(); }
     332             : 
     333             :     //*******************************************
     334             :     // adapt media descriptor, so it contains the right values
     335             :     // for type/filter name/document service/ etcpp.
     336         240 :     impl_checkResultsAndAddBestFilter(stlDescriptor, sType); // Attention: sType is used as IN/OUT param here and will might be changed inside this method !!!
     337         240 :     impl_validateAndSetTypeOnDescriptor(stlDescriptor, sType);
     338             : 
     339         240 :     stlDescriptor >> lDescriptor;
     340         240 :     return sType;
     341             : }
     342             : 
     343             : 
     344             : 
     345         240 : void TypeDetection::impl_checkResultsAndAddBestFilter(::comphelper::MediaDescriptor& rDescriptor,
     346             :                                                       ::rtl::OUString&               sType      )
     347             : {
     348             :     // a)
     349             :     // Dont overwrite a might preselected filter!
     350             :     ::rtl::OUString sFilter = rDescriptor.getUnpackedValueOrDefault(
     351         240 :                                 ::comphelper::MediaDescriptor::PROP_FILTERNAME(),
     352         480 :                                 ::rtl::OUString());
     353         240 :     if (!sFilter.isEmpty())
     354             :         return;
     355             : 
     356             :     // b)
     357             :     // check a preselected document service too.
     358             :     // Then we have to search a suitable filter witin this module.
     359             :     ::rtl::OUString sDocumentService = rDescriptor.getUnpackedValueOrDefault(
     360         240 :                                             ::comphelper::MediaDescriptor::PROP_DOCUMENTSERVICE(),
     361         480 :                                             ::rtl::OUString());
     362         240 :     if (!sDocumentService.isEmpty())
     363             :     {
     364             :         try
     365             :         {
     366           0 :             ::rtl::OUString sRealType = sType;
     367             : 
     368             :             // SAFE ->
     369           0 :             ::osl::ResettableMutexGuard aLock(m_aLock);
     370             : 
     371             :             // Attention: For executing next lines of code, We must be shure that
     372             :             // all filters already loaded :-(
     373             :             // That can disturb our "load on demand feature". But we have no other chance!
     374           0 :             m_rCache->load(FilterCache::E_CONTAINS_FILTERS);
     375             : 
     376           0 :             CacheItem lIProps;
     377           0 :             lIProps[PROPNAME_DOCUMENTSERVICE] <<= sDocumentService;
     378           0 :             lIProps[PROPNAME_TYPE           ] <<= sRealType;
     379           0 :             OUStringList lFilters = m_rCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps);
     380             : 
     381           0 :             aLock.clear();
     382             :             // <- SAFE
     383             : 
     384           0 :             for (OUStringList::const_iterator pIt  = lFilters.begin();
     385           0 :                   pIt != lFilters.end(); ++pIt)
     386             :             {
     387             :                 // SAFE ->
     388           0 :                 aLock.reset();
     389             :                 try
     390             :                 {
     391           0 :                     CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, *pIt);
     392           0 :                     sal_Int32 nFlags  = 0;
     393           0 :                     aFilter[PROPNAME_FLAGS] >>= nFlags;
     394             : 
     395           0 :                     if ((nFlags & FLAGVAL_IMPORT) == FLAGVAL_IMPORT)
     396           0 :                         sFilter = *pIt;
     397           0 :                     if ((nFlags & FLAGVAL_PREFERRED) == FLAGVAL_PREFERRED)
     398           0 :                         break;
     399             :                 }
     400           0 :                 catch(const css::uno::Exception&) {}
     401           0 :                 aLock.clear();
     402             :                 // <- SAFE
     403             :             }
     404             : 
     405           0 :             if (!sFilter.isEmpty())
     406             :             {
     407           0 :                 rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME()  ] <<= sRealType;
     408           0 :                 rDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
     409           0 :                 sType = sRealType;
     410             :                 return;
     411           0 :             }
     412             :         }
     413           0 :         catch(const css::uno::Exception&)
     414             :             {}
     415             :     }
     416             : 
     417             :     // c)
     418             :     // We can use the preferred filter for the specified type.
     419             :     // Such preferred filter points:
     420             :     // - to the default filter of the preferred application
     421             :     // - or to any other filter if no preferred filter was set.
     422             :     // Note: It's an optimization only!
     423             :     // It's not guaranteed, that such preferred filter exists.
     424         240 :     sFilter = ::rtl::OUString();
     425             :     try
     426             :     {
     427             :         // SAFE ->
     428         240 :         ::osl::ResettableMutexGuard aLock(m_aLock);
     429             : 
     430         240 :         CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sType);
     431         237 :         aType[PROPNAME_PREFERREDFILTER] >>= sFilter;
     432         237 :         CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter);
     433             : 
     434         237 :         aLock.clear();
     435             :         // <- SAFE
     436             : 
     437             :         // no exception => found valid type and filter => set it on the given descriptor
     438         237 :         rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME()  ] <<= sType  ;
     439         237 :         rDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
     440         237 :         return;
     441             :     }
     442           3 :     catch(const css::uno::Exception&)
     443             :         {}
     444             : 
     445             :     // d)
     446             :     // Search for any import(!) filter, which is registered for this type.
     447           3 :     sFilter = ::rtl::OUString();
     448             :     try
     449             :     {
     450             :         // SAFE ->
     451           3 :         ::osl::ResettableMutexGuard aLock(m_aLock);
     452             : 
     453             :         // Attention: For executing next lines of code, We must be shure that
     454             :         // all filters already loaded :-(
     455             :         // That can disturb our "load on demand feature". But we have no other chance!
     456           3 :         m_rCache->load(FilterCache::E_CONTAINS_FILTERS);
     457             : 
     458           3 :         CacheItem lIProps;
     459           3 :         lIProps[PROPNAME_TYPE] <<= sType;
     460           3 :         OUStringList lFilters = m_rCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps);
     461             : 
     462           3 :         aLock.clear();
     463             :         // <- SAFE
     464             : 
     465           3 :         OUStringList::const_iterator pIt;
     466           9 :         for (  pIt  = lFilters.begin();
     467           6 :                pIt != lFilters.end()  ;
     468             :              ++pIt                    )
     469             :         {
     470           0 :             sFilter = *pIt;
     471             : 
     472             :             // SAFE ->
     473           0 :             aLock.reset();
     474             :             try
     475             :             {
     476           0 :                 CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter);
     477           0 :                 sal_Int32 nFlags  = 0;
     478           0 :                 aFilter[PROPNAME_FLAGS] >>= nFlags;
     479             : 
     480           0 :                 if ((nFlags & FLAGVAL_IMPORT) == FLAGVAL_IMPORT)
     481           0 :                     break;
     482             :             }
     483           0 :             catch(const css::uno::Exception&)
     484           0 :                 { continue; }
     485           0 :             aLock.clear();
     486             :             // <- SAFE
     487             : 
     488           0 :             sFilter = ::rtl::OUString();
     489             :         }
     490             : 
     491           3 :         if (!sFilter.isEmpty())
     492             :         {
     493           0 :             rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME()  ] <<= sType  ;
     494           0 :             rDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
     495             :             return;
     496           3 :         }
     497             :     }
     498           0 :     catch(const css::uno::Exception&)
     499         240 :         {}
     500             : }
     501             : 
     502             : 
     503             : 
     504           0 : sal_Bool TypeDetection::impl_getPreselectionForType(const ::rtl::OUString& sPreSelType,
     505             :                                                     const css::util::URL&  aParsedURL ,
     506             :                                                           FlatDetection&   rFlatTypes )
     507             : {
     508             :     // Can be used to supress execution of some parts of this method
     509             :     // if its already clear that detected type is valid or not.
     510             :     // Its neccessary to use shared code at the end, which update
     511             :     // all return parameters constistency!
     512           0 :     sal_Bool bBreakDetection = sal_False;
     513             : 
     514             :     // Further we must know if it matches by pattern
     515             :     // Every flat detected type by pattern wont be detected deep!
     516           0 :     sal_Bool bMatchByPattern = sal_False;
     517             : 
     518             :     // And we must know if a preselection must be preferred, because
     519             :     // it matches by it's extension too.
     520           0 :     sal_Bool bMatchByExtension = sal_False;
     521             : 
     522             :     // If we e.g. collect all filters of a factory (be a forced factory preselection)
     523             :     // we should preferr all filters of this factory, where the type match the given URL.
     524             :     // All other types (which sorrespond to filters of the same factory - but dont match
     525             :     // the URL) should be "used later" for detection and sorted at the end of our return vector
     526             :     // rFlatTypes!
     527             :     // => bPreferredPreselection = (matchByExtension || matchByURLPattern)
     528           0 :     sal_Bool bPreferredPreselection = sal_False;
     529             : 
     530             :     // validate type
     531           0 :     ::rtl::OUString sType(sPreSelType);
     532           0 :     CacheItem       aType;
     533             :     try
     534             :     {
     535             :         // SAFE -> --------------------------
     536           0 :         ::osl::ResettableMutexGuard aLock(m_aLock);
     537           0 :         aType = m_rCache->getItem(FilterCache::E_TYPE, sType);
     538           0 :         aLock.clear();
     539             :         // <- SAFE --------------------------
     540             :     }
     541           0 :     catch(const css::container::NoSuchElementException&)
     542             :     {
     543           0 :         sType = ::rtl::OUString();
     544           0 :         bBreakDetection = sal_True;
     545             :     }
     546             : 
     547           0 :     if (!bBreakDetection)
     548             :     {
     549             :         // We cant check a preselected type for a given stream!
     550             :         // So we must believe, that it can work ...
     551           0 :         if ( aParsedURL.Complete == "private:stream" )
     552           0 :             bBreakDetection = sal_True;
     553             :     }
     554             : 
     555           0 :     if (!bBreakDetection)
     556             :     {
     557             :         // extract extension from URL .. to check it case-insensitive !
     558           0 :         INetURLObject   aParser    (aParsedURL.Main);
     559             :         ::rtl::OUString sExtension = aParser.getExtension(INetURLObject::LAST_SEGMENT       ,
     560             :                                                           sal_True                          ,
     561           0 :                                                           INetURLObject::DECODE_WITH_CHARSET);
     562           0 :         sExtension = sExtension.toAsciiLowerCase();
     563             : 
     564             :         // otherwhise we must know, if it matches to the given URL realy.
     565             :         // especialy if it matches by its extension or pattern registration.
     566           0 :         OUStringList lExtensions(aType[PROPNAME_EXTENSIONS]);
     567           0 :         OUStringList lURLPattern(aType[PROPNAME_URLPATTERN]);
     568             : 
     569           0 :         for (OUStringList::const_iterator pIt  = lExtensions.begin();
     570           0 :                                           pIt != lExtensions.end()  ;
     571             :                                         ++pIt                       )
     572             :         {
     573           0 :             ::rtl::OUString sCheckExtension(pIt->toAsciiLowerCase());
     574           0 :             if (sCheckExtension.equals(sExtension))
     575             :             {
     576           0 :                 bBreakDetection        = sal_True;
     577           0 :                 bMatchByExtension      = sal_True;
     578           0 :                 bPreferredPreselection = sal_True;
     579             :                 break;
     580             :             }
     581           0 :         }
     582             : 
     583           0 :         if (!bBreakDetection)
     584             :         {
     585           0 :             for (OUStringList::const_iterator pIt  = lURLPattern.begin();
     586           0 :                                               pIt != lURLPattern.end()  ;
     587             :                                             ++pIt                       )
     588             :             {
     589           0 :                 WildCard aCheck(*pIt);
     590           0 :                 if (aCheck.Matches(aParsedURL.Main))
     591             :                 {
     592           0 :                     bBreakDetection        = sal_True;
     593           0 :                     bMatchByPattern        = sal_True;
     594           0 :                     bPreferredPreselection = sal_True;
     595             :                     break;
     596             :                 }
     597           0 :             }
     598           0 :         }
     599             :     }
     600             : 
     601             :     // if its a valid type - set it on all return values!
     602           0 :     if (!sType.isEmpty())
     603             :     {
     604           0 :         FlatDetectionInfo aInfo;
     605           0 :         aInfo.sType              = sType;
     606           0 :         aInfo.bMatchByExtension  = bMatchByExtension;
     607           0 :         aInfo.bMatchByPattern    = bMatchByPattern;
     608             : 
     609           0 :         if (bPreferredPreselection)
     610           0 :             rFlatTypes.push_front(aInfo);
     611             :         else
     612           0 :             rFlatTypes.push_back(aInfo);
     613             : 
     614           0 :         return sal_True;
     615             :     }
     616             : 
     617             :     // not valid!
     618           0 :     return sal_False;
     619             : }
     620             : 
     621             : 
     622             : 
     623           0 : sal_Bool TypeDetection::impl_getPreselectionForFilter(const ::rtl::OUString& sPreSelFilter,
     624             :                                                       const css::util::URL&  aParsedURL   ,
     625             :                                                             FlatDetection&   rFlatTypes   )
     626             : {
     627             :     // Can be used to supress execution of some parts of this method
     628             :     // if its already clear that detected filter is valid or not.
     629             :     // Its neccessary to use shared code at the end, which update
     630             :     // all return parameters constistency!
     631           0 :     sal_Bool bBreakDetection = sal_False;
     632             : 
     633             :     // validate filter
     634           0 :     ::rtl::OUString sFilter(sPreSelFilter);
     635           0 :     CacheItem       aFilter;
     636             :     try
     637             :     {
     638             :         // SAFE -> --------------------------
     639           0 :         ::osl::ResettableMutexGuard aLock(m_aLock);
     640           0 :         aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter);
     641           0 :         aLock.clear();
     642             :         // <- SAFE --------------------------
     643             :     }
     644           0 :     catch(const css::container::NoSuchElementException&)
     645             :     {
     646           0 :         sFilter = ::rtl::OUString();
     647           0 :         bBreakDetection = sal_True;
     648             :     }
     649             : 
     650           0 :     if (!bBreakDetection)
     651             :     {
     652             :         // get its type and check if it matches the given URL
     653           0 :         ::rtl::OUString sType;
     654           0 :         aFilter[PROPNAME_TYPE] >>= sType;
     655             : 
     656           0 :         bBreakDetection = impl_getPreselectionForType(sType, aParsedURL, rFlatTypes);
     657             : 
     658             :         // not a valid type? -> not a valid filter!
     659           0 :         if (!bBreakDetection)
     660           0 :             sFilter = ::rtl::OUString();
     661             :     }
     662             : 
     663           0 :     if (!sFilter.isEmpty())
     664           0 :         return sal_True;
     665             :     else
     666           0 :         return sal_False;
     667             : }
     668             : 
     669             : 
     670             : 
     671           0 : sal_Bool TypeDetection::impl_getPreselectionForDocumentService(const ::rtl::OUString& sPreSelDocumentService,
     672             :                                                                const css::util::URL&  aParsedURL            ,
     673             :                                                                      FlatDetection&   rFlatTypes            )
     674             : {
     675             :     // get all filters, which match to this doc service
     676           0 :     OUStringList lFilters;
     677             :     try
     678             :     {
     679             :         // SAFE -> --------------------------
     680           0 :         ::osl::ResettableMutexGuard aLock(m_aLock);
     681             : 
     682             :         // Attention: For executing next lines of code, We must be shure that
     683             :         // all filters already loaded :-(
     684             :         // That can disturb our "load on demand feature". But we have no other chance!
     685           0 :         m_rCache->load(FilterCache::E_CONTAINS_FILTERS);
     686             : 
     687           0 :         CacheItem lIProps;
     688           0 :         lIProps[PROPNAME_DOCUMENTSERVICE] <<= sPreSelDocumentService;
     689           0 :         lFilters = m_rCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps);
     690             : 
     691           0 :         aLock.clear();
     692             :         // <- SAFE --------------------------
     693             :     }
     694           0 :     catch(const css::container::NoSuchElementException&)
     695             :     {
     696           0 :         lFilters.clear();
     697             :     }
     698             : 
     699             :     // step over all filters, and check if its registered type
     700             :     // match the given URL.
     701             :     // But use temp. list of "preselected types" instead of incoming rFlatTypes list!
     702             :     // The reason behind: we must filter the getted results. And copying of stl entries
     703             :     // is an easier job then removing it .-)
     704           0 :     FlatDetection lPreselections;
     705           0 :     for (OUStringList::const_iterator pFilter  = lFilters.begin();
     706           0 :                                       pFilter != lFilters.end()  ;
     707             :                                     ++pFilter                    )
     708             :     {
     709           0 :         const ::rtl::OUString sFilter = *pFilter;
     710           0 :         impl_getPreselectionForFilter(sFilter, aParsedURL, lPreselections);
     711           0 :     }
     712             : 
     713             :     // We have to mark all retrieved preselection items as "preselected by document service".
     714             :     // Further we must ignore all preselected items, which does not match the URL!
     715           0 :     FlatDetection::iterator pIt;
     716           0 :     for (  pIt  = lPreselections.begin();
     717           0 :            pIt != lPreselections.end()  ;
     718             :          ++pIt                          )
     719             :     {
     720           0 :         FlatDetectionInfo& rInfo = *pIt;
     721           0 :         rInfo.bPreselectedByDocumentService = sal_True ;
     722           0 :         rFlatTypes.push_back(rInfo);
     723             :     }
     724             : 
     725           0 :     return sal_True;
     726             : }
     727             : 
     728             : 
     729             : 
     730         240 : void TypeDetection::impl_getPreselection(const css::util::URL&                aParsedURL ,
     731             :                                                ::comphelper::MediaDescriptor& rDescriptor,
     732             :                                                FlatDetection&                 rFlatTypes )
     733             : {
     734             :     // done to be shure, that only valid results leave this function!
     735         240 :     rFlatTypes.clear();
     736             : 
     737             :     /* #i55122#
     738             :         Sometimes we must detect files without or with real unknown extensions.
     739             :         If it does not work /which can happen of course .-)/, the user tried to preselect
     740             :         the right format. But some special dialogs (e.g. "Insert->Sheet From File")
     741             :         add it's own preselection too.
     742             :         So we have a combination of preselected values ...
     743             : 
     744             :         The we should preferr the most important one - set by the user.
     745             :         And the user normaly preselects a filter or type. The preslected
     746             :         document service cames from the dialog.
     747             : 
     748             :         Further it doesnt matter if the user preselected a filter or a document service.
     749             :         A filter selection is always more explicit then a document service selection.
     750             :         So it must be pereferred. An order between type and filter selection cant be discussed .-)
     751             :     */
     752             : 
     753         240 :     ::rtl::OUString sSelectedType = rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_TYPENAME(), ::rtl::OUString());
     754         240 :     if (!sSelectedType.isEmpty())
     755           0 :         impl_getPreselectionForType(sSelectedType, aParsedURL, rFlatTypes);
     756             : 
     757         240 :     ::rtl::OUString sSelectedDoc = rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_DOCUMENTSERVICE(), ::rtl::OUString());
     758         240 :     if (!sSelectedDoc.isEmpty())
     759           0 :         impl_getPreselectionForDocumentService(sSelectedDoc, aParsedURL, rFlatTypes);
     760         240 : }
     761             : 
     762             : 
     763             : 
     764         182 : ::rtl::OUString TypeDetection::impl_detectTypeFlatAndDeep(      ::comphelper::MediaDescriptor& rDescriptor   ,
     765             :                                                           const FlatDetection&                 lFlatTypes    ,
     766             :                                                                 sal_Bool                       bAllowDeep    ,
     767             :                                                                 OUStringList&                  rUsedDetectors,
     768             :                                                                 ::rtl::OUString&               rLastChance   )
     769             : {
     770             :     // reset it everytimes, so the outside code can distinguish between
     771             :     // a set and a not set value.
     772         182 :     rLastChance = ::rtl::OUString();
     773         182 :     rUsedDetectors.clear();
     774             : 
     775             :     // step over all possible types for this URL.
     776             :     // solutions:
     777             :     // a) no types                                => no detection
     778             :     // b) deep detection not allowed              => return first valid type of list (because its the preferred or the first valid one)
     779             :     //    or(!) match by URLPattern               => in such case a deep detection will be supressed!
     780             :     // c) type has no detect service              => safe the first occurred type without a detect service
     781             :     //                                               as "last chance"(!). It will be used outside of this method
     782             :     //                                               if no further type could be detected.
     783             :     //                                               It must be the first one, because it can be a preferred type.
     784             :     //                                               Our types list was sorted by such criteria!
     785             :     // d) detect service return a valid result    => return its decision
     786             :     // e) detect service return an invalid result
     787             :     //    or any needed information could not be
     788             :     //    getted from the cache                   => ignore it, and continue with search
     789             : 
     790         546 :     for (FlatDetection::const_iterator pFlatIt  = lFlatTypes.begin();
     791         364 :                                        pFlatIt != lFlatTypes.end()  ;
     792             :                                      ++pFlatIt                      )
     793             :     {
     794         182 :         const FlatDetectionInfo& aFlatTypeInfo = *pFlatIt;
     795         182 :               ::rtl::OUString    sFlatType     = aFlatTypeInfo.sType;
     796             : 
     797         182 :         if (!impl_validateAndSetTypeOnDescriptor(rDescriptor, sFlatType))
     798           0 :             continue;
     799             : 
     800             :         // b)
     801         182 :         if (
     802             :             (!bAllowDeep                  ) ||
     803             :             (aFlatTypeInfo.bMatchByPattern)
     804             :            )
     805             :         {
     806           0 :             return sFlatType;
     807             :         }
     808             : 
     809             :         try
     810             :         {
     811             :             // SAFE -> ----------------------------------
     812         182 :             ::osl::ResettableMutexGuard aLock(m_aLock);
     813         182 :             CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sFlatType);
     814         182 :             aLock.clear();
     815             : 
     816         182 :             ::rtl::OUString sDetectService;
     817         182 :             aType[PROPNAME_DETECTSERVICE] >>= sDetectService;
     818             : 
     819             :             // c)
     820         182 :             if (sDetectService.isEmpty())
     821             :             {
     822             :                 // flat detected types without any registered deep detection service and not
     823             :                 // preselected by the user can be used as LAST CHANCE in case no other type could
     824             :                 // be detected. Of course only the first type without deep detector can be used.
     825             :                 // Further ones has to be ignored.
     826           0 :                 if (rLastChance.isEmpty())
     827           0 :                     rLastChance = sFlatType;
     828             : 
     829           0 :                 continue;
     830             :             }
     831             : 
     832             :             // dont forget to add every real asked deep detection service here.
     833             :             // Such detectors will be ignored if may be "impl_detectTypeDeepOnly()"
     834             :             // must be called later!
     835         182 :             rUsedDetectors.push_back(sDetectService);
     836         182 :             ::rtl::OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor);
     837             : 
     838             :             // d)
     839         182 :             if (!sDeepType.isEmpty())
     840         182 :                 return sDeepType;
     841             :         }
     842           0 :         catch(const css::container::NoSuchElementException&)
     843             :             {}
     844             :         // e)
     845         182 :     }
     846             : 
     847           0 :     return ::rtl::OUString();
     848             :     // <- SAFE ----------------------------------
     849             : }
     850             : 
     851             : //TO-DO: add a priority entry to filter config, e.g. defaulting to 50 and
     852             : //flag externally that some filters are lower e.g. 25 and are catch-alls
     853             : //to be tried last. Split up writer/calc/etc. filter detection to standalone
     854             : //those problematic formats
     855             : namespace
     856             : {
     857        7482 :     bool sort_catchalls_to_end(const rtl::OUString& rA, const rtl::OUString& rB)
     858             :     {
     859        7482 :         if (rA == rB)
     860           0 :             return false;
     861        7482 :         if ( rA == "com.sun.star.text.FormatDetector" )
     862         116 :             return false;
     863        7366 :         if ( rB == "com.sun.star.text.FormatDetector" )
     864          58 :             return true;
     865        7308 :         return rA < rB;
     866             :     }
     867             : }
     868             : 
     869          58 : ::rtl::OUString TypeDetection::impl_detectTypeDeepOnly(      ::comphelper::MediaDescriptor& rDescriptor          ,
     870             :                                                        const OUStringList&                  lOutsideUsedDetectors)
     871             : {
     872             :     // We must know if a detect service was already used:
     873             :     //  i) in a combined flat/deep detection scenario outside or
     874             :     // ii) in this method for a deep detection only.
     875             :     // Reason: Such deep detection services work differently in these two modes!
     876          58 :     OUStringList                 lInsideUsedDetectors;
     877          58 :     OUStringList::const_iterator pIt;
     878             : 
     879             :     // a)
     880             :     // The list of "already used detect services" correspond to the list
     881             :     // of preselected or flat detected types. But these detect services was called
     882             :     // to check these types explicitly and return black/white ... yes/no only.
     883             :     // Now they are called to return any possible result. But we should preferr
     884             :     // these already used detect services against all other ones!
     885         174 :     for (  pIt  = lOutsideUsedDetectors.begin();
     886         116 :            pIt != lOutsideUsedDetectors.end()  ;
     887             :          ++pIt                                 )
     888             :     {
     889           0 :         const ::rtl::OUString& sDetectService = *pIt;
     890           0 :               ::rtl::OUString  sDeepType      = impl_askDetectService(sDetectService, rDescriptor);
     891           0 :         if (!sDeepType.isEmpty())
     892           0 :             return sDeepType;
     893           0 :         lInsideUsedDetectors.push_back(sDetectService);
     894           0 :     }
     895             : 
     896             :     // SAFE -> ----------------------------------
     897          58 :     ::osl::ResettableMutexGuard aLock(m_aLock);
     898          58 :     OUStringList lDetectors = m_rCache->getItemNames(FilterCache::E_DETECTSERVICE);
     899          58 :     std::sort(lDetectors.begin(), lDetectors.end(), sort_catchalls_to_end);
     900          58 :     aLock.clear();
     901             :     // <- SAFE ----------------------------------
     902             : 
     903             :     // b)
     904             :     // Sometimes it would be nice to ask a special set of detect services before
     905             :     // any other detect service is asked. E.g. by using a preselection of a DocumentService.
     906             :     // That's needed to prevent us from asking the "wrong application module" and
     907             :     // opening the files into the "wrong application".
     908             :     ::rtl::OUString sPreselDocumentService = rDescriptor.getUnpackedValueOrDefault(
     909          58 :                                                 ::comphelper::MediaDescriptor::PROP_DOCUMENTSERVICE(),
     910         116 :                                                 ::rtl::OUString());
     911          58 :     if (!sPreselDocumentService.isEmpty())
     912             :     {
     913           0 :         for (  pIt  = lDetectors.begin();
     914           0 :                pIt != lDetectors.end()  ;
     915             :              ++pIt                      )
     916             :         {
     917           0 :             const ::rtl::OUString& sDetectService = *pIt;
     918             : 
     919           0 :             OUStringList::const_iterator pAlreadyUsed = ::std::find(lInsideUsedDetectors.begin(), lInsideUsedDetectors.end(), sDetectService);
     920           0 :             if (pAlreadyUsed != lInsideUsedDetectors.end())
     921           0 :                 continue;
     922             : 
     923             :             // SAFE -> --------------------------------------------------------
     924           0 :             aLock.reset();
     925             : 
     926           0 :             CacheItem lIProps;
     927           0 :             lIProps[PROPNAME_DETECTSERVICE] <<= sDetectService;
     928           0 :             OUStringList lTypes = m_rCache->getMatchingItemsByProps(FilterCache::E_TYPE, lIProps);
     929             : 
     930           0 :             aLock.clear();
     931             :             // <- SAFE --------------------------------------------------------
     932             : 
     933           0 :             sal_Bool bMatchDetectorToDocumentService = sal_False;
     934           0 :             OUStringList::const_iterator pIt2;
     935           0 :             for (  pIt2  = lTypes.begin();
     936           0 :                    pIt2 != lTypes.end()  ;
     937             :                  ++pIt2                  )
     938             :             {
     939           0 :                 const ::rtl::OUString& sType  = *pIt2;
     940             : 
     941             :                 try
     942             :                 {
     943             :                     // SAFE -> ----------------------------------------------------
     944           0 :                     aLock.reset();
     945             : 
     946           0 :                     CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sType);
     947           0 :                     ::rtl::OUString sFilter;
     948           0 :                     aType[PROPNAME_PREFERREDFILTER] >>= sFilter;
     949           0 :                     CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter);
     950           0 :                     ::rtl::OUString sCheckDocumentService;
     951           0 :                     aFilter[PROPNAME_DOCUMENTSERVICE] >>= sCheckDocumentService;
     952             : 
     953           0 :                     aLock.clear();
     954             :                     // <- SAFE
     955             : 
     956           0 :                     if (sCheckDocumentService.equals(sPreselDocumentService))
     957             :                     {
     958           0 :                         bMatchDetectorToDocumentService = sal_True;
     959             :                         break;
     960           0 :                     }
     961             :                 }
     962           0 :                 catch(const css::uno::Exception&)
     963           0 :                     { continue; }
     964             :             }
     965             : 
     966           0 :             if (bMatchDetectorToDocumentService)
     967             :             {
     968           0 :                 ::rtl::OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor);
     969           0 :                 if (!sDeepType.isEmpty())
     970           0 :                     return sDeepType;
     971           0 :                 lInsideUsedDetectors.push_back(sDetectService);
     972             :             }
     973           0 :         }
     974             :     }
     975             : 
     976             :     // c)
     977             :     // Last chance. No "used detectors", no "preselected detectors" ... ask any existing detect services
     978             :     // for this till know unknown format.
     979        3519 :     for (  pIt  = lDetectors.begin();
     980        2346 :            pIt != lDetectors.end()  ;
     981             :          ++pIt                      )
     982             :     {
     983        1170 :         const ::rtl::OUString& sDetectService = *pIt;
     984             : 
     985        1170 :         OUStringList::const_iterator pAlreadyUsed = ::std::find(lInsideUsedDetectors.begin(), lInsideUsedDetectors.end(), sDetectService);
     986        1170 :         if (pAlreadyUsed != lInsideUsedDetectors.end())
     987           0 :             continue;
     988             : 
     989        1170 :         ::rtl::OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor);
     990        1170 :         if (!sDeepType.isEmpty())
     991          55 :             return sDeepType;
     992        1170 :     }
     993             : 
     994           3 :     return ::rtl::OUString();
     995             : }
     996             : 
     997        1592 : void TypeDetection::impl_seekStreamToZero(comphelper::MediaDescriptor& rDescriptor)
     998             : {
     999             :     // try to seek to 0 ...
    1000             :     // But because XSeekable is an optional interface ... try it only .-)
    1001             :     css::uno::Reference< css::io::XInputStream > xStream = rDescriptor.getUnpackedValueOrDefault(
    1002        1592 :                                                             ::comphelper::MediaDescriptor::PROP_INPUTSTREAM(),
    1003        3184 :                                                             css::uno::Reference< css::io::XInputStream >());
    1004        1592 :     css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY);
    1005        1592 :     if (xSeek.is())
    1006             :     {
    1007             :         try
    1008             :         {
    1009        1592 :             xSeek->seek(0);
    1010             :         }
    1011           0 :         catch(const css::uno::RuntimeException&)
    1012             :         {
    1013           0 :             throw;
    1014             :         }
    1015           0 :         catch(const css::uno::Exception&)
    1016             :         {
    1017             :         }
    1018        1592 :     }
    1019        1592 : }
    1020             : 
    1021        1352 : ::rtl::OUString TypeDetection::impl_askDetectService(const ::rtl::OUString&               sDetectService,
    1022             :                                                            ::comphelper::MediaDescriptor& rDescriptor   )
    1023             : {
    1024             :     // Open the stream and add it to the media descriptor if this method is called for the first time.
    1025             :     // All following requests to this method will detect, that there already exists a stream .-)
    1026             :     // Attention: This method throws an exception if the stream could not be opened.
    1027             :     // It's important to break any further detection in such case.
    1028             :     // Catch it on the highest detection level only !!!
    1029        1352 :     impl_openStream(rDescriptor);
    1030             : 
    1031             :     // seek to 0 is an optional feature to be more robust against
    1032             :     // "simple implemented detect services" .-)
    1033        1352 :     impl_seekStreamToZero(rDescriptor);
    1034             : 
    1035        1352 :     css::uno::Reference< css::document::XExtendedFilterDetection > xDetector;
    1036        1352 :     css::uno::Reference< css::lang::XMultiServiceFactory >         xSMGR;
    1037             : 
    1038             :     // SAFE ->
    1039        1352 :     ::osl::ResettableMutexGuard aLock(m_aLock);
    1040        1352 :     xSMGR = m_xSMGR;
    1041        1352 :     aLock.clear();
    1042             :     // <- SAFE
    1043             : 
    1044             :     try
    1045             :     {
    1046             :         // Attention! If e.g. an office module was not installed sometimes we
    1047             :         // find a registered detect service, which is referred inside the
    1048             :         // configuration ... but not realy installed. On the other side we use
    1049             :         // third party components here, which can make trouble anyway.  So we
    1050             :         // should handle errors during creation of such services more
    1051             :         // gracefully .-)
    1052             :         xDetector = css::uno::Reference< css::document::XExtendedFilterDetection >(
    1053        1352 :                 xSMGR->createInstance(sDetectService),
    1054        1352 :                 css::uno::UNO_QUERY_THROW);
    1055             :     }
    1056        1112 :     catch (...)
    1057             :     {
    1058             :     }
    1059             : 
    1060        1352 :     if ( ! xDetector.is())
    1061        1112 :         return ::rtl::OUString();
    1062             : 
    1063         240 :     ::rtl::OUString sDeepType;
    1064             :     try
    1065             :     {
    1066             :         // start deep detection
    1067             :         // Dont forget to convert stl descriptor to its uno representation.
    1068             : 
    1069             :         /* Attention!
    1070             :                 You have to use an explicit instance of this uno sequence ...
    1071             :                 Because its used as an in out parameter. And in case of a temp. used object
    1072             :                 we will run into memory corruptions!
    1073             :         */
    1074         240 :         css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
    1075         240 :         rDescriptor >> lDescriptor;
    1076         240 :         sDeepType = xDetector->detect(lDescriptor);
    1077         240 :         rDescriptor << lDescriptor;
    1078             :     }
    1079           0 :     catch(const css::uno::Exception&)
    1080             :         {
    1081             :             // We should ignore errors here.
    1082             :             // Thrown exceptions mostly will end in crash recovery ...
    1083             :             // But might be we find another deep detection service which can detect the same
    1084             :             // document without a problem .-)
    1085           0 :             sDeepType = ::rtl::OUString();
    1086             :         }
    1087             : 
    1088             :     // seek to 0 is an optional feature to be more robust against
    1089             :     // "simple implemented detect services" .-)
    1090         240 :     impl_seekStreamToZero(rDescriptor);
    1091             : 
    1092             :     // analyze the results
    1093             :     // a) detect service returns "" => return "" too and remove TYPE/FILTER prop from descriptor
    1094             :     // b) returned type is unknown  => return "" too and remove TYPE/FILTER prop from descriptor
    1095             :     // c) returned type is valid    => check TYPE/FILTER props inside descriptor and return the type
    1096             : 
    1097             :     // this special helper checks for a valid type
    1098             :     // and set right values on the descriptor!
    1099         240 :     sal_Bool bValidType = impl_validateAndSetTypeOnDescriptor(rDescriptor, sDeepType);
    1100         240 :     if (bValidType)
    1101         237 :         return sDeepType;
    1102             : 
    1103           3 :     return ::rtl::OUString();
    1104             : }
    1105             : 
    1106             : 
    1107             : 
    1108           3 : ::rtl::OUString TypeDetection::impl_askUserForTypeAndFilterIfAllowed(::comphelper::MediaDescriptor& rDescriptor)
    1109             : {
    1110             :     // SAFE ->
    1111           3 :     ::osl::ResettableMutexGuard aLock(m_aLock);
    1112           3 :     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
    1113           3 :     aLock.clear();
    1114             :     // <- SAFE
    1115             : 
    1116             :     css::uno::Reference< css::task::XInteractionHandler > xInteraction =
    1117           3 :         rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_INTERACTIONHANDLER(),
    1118           6 :         css::uno::Reference< css::task::XInteractionHandler >());
    1119             : 
    1120           3 :     if (!xInteraction.is())
    1121           3 :         return ::rtl::OUString();
    1122             : 
    1123             :     ::rtl::OUString sURL =
    1124           0 :         rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_URL(),
    1125           0 :         ::rtl::OUString());
    1126             : 
    1127             :     css::uno::Reference< css::io::XInputStream > xStream =
    1128           0 :         rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_INPUTSTREAM(),
    1129           0 :         css::uno::Reference< css::io::XInputStream >());
    1130             : 
    1131             :     // Dont distrub the user for "non existing files - means empty URLs" or
    1132             :     // if we was forced to detect a stream.
    1133             :     // Reason behind: We must be shure to ask user for "unknown contents" only ...
    1134             :     // and not for "missing files". Especialy if detection is done by a stream only
    1135             :     // we cant check if the stream points to an "existing content"!
    1136           0 :     if (
    1137           0 :         (sURL.isEmpty()                                     ) || // "non existing file" ?
    1138           0 :         (!xStream.is()                                         ) || // non existing file !
    1139           0 :         (sURL.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("private:stream")))    // not a good idea .-)
    1140             :        )
    1141           0 :         return ::rtl::OUString();
    1142             : 
    1143             :     try
    1144             :     {
    1145             :         // create a new request to ask user for it's decision about the usable filter
    1146           0 :         ::framework::RequestFilterSelect aRequest(sURL);
    1147           0 :         xInteraction->handle(aRequest.GetRequest());
    1148             : 
    1149             :         // "Cancel" pressed? => return with error
    1150           0 :         if (aRequest.isAbort())
    1151           0 :             return ::rtl::OUString();
    1152             : 
    1153             :         // "OK" pressed => verify the selected filter, get it's coressponding
    1154             :         // type and return it. (BTW: We must update the media descriptor here ...)
    1155             :         // The user selected explicitly a filter ... but normaly we are interested on
    1156             :         // a type here only. But we must be shure, that the selected filter is used
    1157             :         // too and no ambigous filter registration disturb us .-)
    1158             : 
    1159           0 :         ::rtl::OUString sFilter = aRequest.getFilter();
    1160           0 :         if (!impl_validateAndSetFilterOnDescriptor(rDescriptor, sFilter))
    1161           0 :             return ::rtl::OUString();
    1162             : 
    1163           0 :         ::rtl::OUString sType;
    1164           0 :         rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME()] >>= sType;
    1165           0 :         return sType;
    1166             :     }
    1167           0 :     catch(const css::uno::Exception&)
    1168             :         {}
    1169             : 
    1170           0 :     return ::rtl::OUString();
    1171             : }
    1172             : 
    1173             : 
    1174             : 
    1175        1352 : void TypeDetection::impl_openStream(::comphelper::MediaDescriptor& rDescriptor)
    1176             :     throw (css::uno::Exception)
    1177             : {
    1178        1352 :     sal_Bool bSuccess = sal_False;
    1179        1352 :     ::rtl::OUString sURL = rDescriptor.getUnpackedValueOrDefault( ::comphelper::MediaDescriptor::PROP_URL(), ::rtl::OUString() );
    1180        1352 :     sal_Bool bRequestedReadOnly = rDescriptor.getUnpackedValueOrDefault( ::comphelper::MediaDescriptor::PROP_READONLY(), sal_False );
    1181        1352 :     if ( !sURL.isEmpty() && ::utl::LocalFileHelper::IsLocalFile( INetURLObject( sURL ).GetMainURL( INetURLObject::NO_DECODE ) ) )
    1182             :     {
    1183             :         // OOo uses own file locking mechanics in case of local file
    1184        1289 :         bSuccess = rDescriptor.addInputStreamOwnLock();
    1185             :     }
    1186             :     else
    1187          63 :         bSuccess = rDescriptor.addInputStream();
    1188             : 
    1189        1352 :     if ( !bSuccess )
    1190           0 :         throw css::uno::Exception(_FILTER_CONFIG_FROM_ASCII_("Could not open stream."), static_cast< css::document::XTypeDetection* >(this));
    1191             : 
    1192        1352 :     if ( !bRequestedReadOnly )
    1193             :     {
    1194             :         // The MediaDescriptor implementation adds ReadOnly argument if the file can not be opened for writing
    1195             :         // this argument should be either removed or an additional argument should be added so that application
    1196             :         // can separate the case when the user explicitly requests readonly document.
    1197             :         // The current solution is to remove it here.
    1198        1352 :         rDescriptor.erase( ::comphelper::MediaDescriptor::PROP_READONLY() );
    1199        1352 :     }
    1200        1352 : }
    1201             : 
    1202             : 
    1203             : 
    1204           6 : void TypeDetection::impl_removeTypeFilterFromDescriptor(::comphelper::MediaDescriptor& rDescriptor)
    1205             : {
    1206           6 :     ::comphelper::MediaDescriptor::iterator pItType   = rDescriptor.find(::comphelper::MediaDescriptor::PROP_TYPENAME()  );
    1207           6 :     ::comphelper::MediaDescriptor::iterator pItFilter = rDescriptor.find(::comphelper::MediaDescriptor::PROP_FILTERNAME());
    1208           6 :     if (pItType != rDescriptor.end())
    1209           0 :         rDescriptor.erase(pItType);
    1210           6 :     if (pItFilter != rDescriptor.end())
    1211           0 :         rDescriptor.erase(pItFilter);
    1212           6 : }
    1213             : 
    1214             : 
    1215             : 
    1216         662 : sal_Bool TypeDetection::impl_validateAndSetTypeOnDescriptor(      ::comphelper::MediaDescriptor& rDescriptor,
    1217             :                                                             const ::rtl::OUString&               sType      )
    1218             : {
    1219             :     // SAFE ->
    1220         662 :     ::osl::ResettableMutexGuard aLock(m_aLock);
    1221         662 :     if (m_rCache->hasItem(FilterCache::E_TYPE, sType))
    1222             :     {
    1223         656 :         rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME()] <<= sType;
    1224         656 :         return sal_True;
    1225             :     }
    1226           6 :     aLock.clear();
    1227             :     // <- SAFE
    1228             : 
    1229             :     // remove all related informations from the descriptor
    1230           6 :     impl_removeTypeFilterFromDescriptor(rDescriptor);
    1231           6 :     return sal_False;
    1232             : }
    1233             : 
    1234             : 
    1235             : 
    1236           0 : sal_Bool TypeDetection::impl_validateAndSetFilterOnDescriptor(      ::comphelper::MediaDescriptor& rDescriptor,
    1237             :                                                               const ::rtl::OUString&               sFilter    )
    1238             : {
    1239             :     try
    1240             :     {
    1241             :         // SAFE ->
    1242           0 :         ::osl::ResettableMutexGuard aLock(m_aLock);
    1243             : 
    1244           0 :         CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter);
    1245           0 :         ::rtl::OUString sType;
    1246           0 :         aFilter[PROPNAME_TYPE] >>= sType;
    1247           0 :         CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sType);
    1248             : 
    1249           0 :         aLock.clear();
    1250             :         // <- SAFE
    1251             : 
    1252             :         // found valid type and filter => set it on the given descriptor
    1253           0 :         rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME()  ] <<= sType  ;
    1254           0 :         rDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
    1255           0 :         return sal_True;
    1256             :     }
    1257           0 :     catch(const css::container::NoSuchElementException&){}
    1258             : 
    1259             :     // remove all related informations from the descriptor
    1260           0 :     impl_removeTypeFilterFromDescriptor(rDescriptor);
    1261           0 :     return sal_False;
    1262             : }
    1263             : 
    1264             : 
    1265             : 
    1266        5614 : ::rtl::OUString TypeDetection::impl_getImplementationName()
    1267             : {
    1268        5614 :     return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.filter.config.TypeDetection" ));
    1269             : }
    1270             : 
    1271             : 
    1272             : 
    1273        5559 : css::uno::Sequence< ::rtl::OUString > TypeDetection::impl_getSupportedServiceNames()
    1274             : {
    1275        5559 :     css::uno::Sequence< ::rtl::OUString > lServiceNames(1);
    1276        5559 :     lServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.TypeDetection" ));
    1277        5559 :     return lServiceNames;
    1278             : }
    1279             : 
    1280             : 
    1281             : 
    1282        5546 : css::uno::Reference< css::uno::XInterface > SAL_CALL TypeDetection::impl_createInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
    1283             : {
    1284        5546 :     TypeDetection* pNew = new TypeDetection(xSMGR);
    1285        5546 :     return css::uno::Reference< css::uno::XInterface >(static_cast< css::document::XTypeDetection* >(pNew), css::uno::UNO_QUERY);
    1286             : }
    1287             : 
    1288             :     } // namespace config
    1289             : } // namespace filter
    1290             : 
    1291             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10