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

Generated by: LCOV version 1.10