LCOV - code coverage report
Current view: top level - filter/source/config/cache - typedetection.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 350 417 83.9 %
Date: 2015-06-13 12:38:46 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             : #include <comphelper/sequence.hxx>
      37             : 
      38             : #define DEBUG_TYPE_DETECTION 0
      39             : 
      40             : #if DEBUG_TYPE_DETECTION
      41             : #include <iostream>
      42             : using std::cout;
      43             : using std::endl;
      44             : #endif
      45             : 
      46             : using namespace com::sun::star;
      47             : 
      48             : namespace filter{
      49             :     namespace config{
      50             : 
      51       44102 : TypeDetection::TypeDetection(const css::uno::Reference< css::uno::XComponentContext >& rxContext)
      52       44102 :    : m_xContext(rxContext)
      53             : {
      54             :     BaseContainer::init(rxContext                                     ,
      55             :                         TypeDetection::impl_getImplementationName()   ,
      56             :                         TypeDetection::impl_getSupportedServiceNames(),
      57       44102 :                         FilterCache::E_TYPE                           );
      58       44102 : }
      59             : 
      60             : 
      61             : 
      62       88204 : TypeDetection::~TypeDetection()
      63             : {
      64       88204 : }
      65             : 
      66             : 
      67             : 
      68       23158 : OUString SAL_CALL TypeDetection::queryTypeByURL(const OUString& sURL)
      69             :     throw (css::uno::RuntimeException, std::exception)
      70             : {
      71       23158 :     OUString sType;
      72             : 
      73             :     // SAFE ->
      74       46316 :     ::osl::ResettableMutexGuard aLock(m_aLock);
      75             : 
      76       46316 :     css::util::URL  aURL;
      77       23158 :     aURL.Complete = sURL;
      78       46316 :     css::uno::Reference< css::util::XURLTransformer > xParser( css::util::URLTransformer::create(m_xContext) );
      79       23158 :     xParser->parseStrict(aURL);
      80             : 
      81             :     // set std types as minimum requirement first!
      82             :     // Only in case no type was found for given URL,
      83             :     // use optional types too ...
      84       46316 :     FlatDetection lFlatTypes;
      85       23158 :     m_rCache->detectFlatForURL(aURL, lFlatTypes);
      86             : 
      87       23158 :     if (
      88       44468 :         (lFlatTypes.size() < 1                                ) &&
      89       21310 :         (!m_rCache->isFillState(FilterCache::E_CONTAINS_TYPES))
      90             :        )
      91             :     {
      92           4 :         m_rCache->load(FilterCache::E_CONTAINS_TYPES);
      93           4 :         m_rCache->detectFlatForURL(aURL, lFlatTypes);
      94             :     }
      95             : 
      96             :     // first item is guaranteed as "preferred" one!
      97       23158 :     if (lFlatTypes.size() > 0)
      98             :     {
      99        1848 :         const FlatDetectionInfo& aMatch = *(lFlatTypes.begin());
     100        1848 :         sType = aMatch.sType;
     101             :     }
     102             : 
     103       46316 :     return sType;
     104             :     // <- SAFE
     105             : }
     106             : 
     107             : namespace {
     108             : 
     109             : /**
     110             :  * Rank format types in order of complexity.  More complex formats are
     111             :  * ranked higher so that they get tested sooner over simpler formats.
     112             :  *
     113             :  * Guidelines to determine how complex a format is (subject to change):
     114             :  *
     115             :  * 1) compressed text (XML, HTML, etc)
     116             :  * 2) binary
     117             :  * 3) non-compressed text
     118             :  *   3.1) structured text
     119             :  *     3.1.1) dialect of a structured text (e.g. docbook XML)
     120             :  *     3.1.2) generic structured text (e.g. generic XML)
     121             :  *   3.2) non-structured text
     122             :  *
     123             :  * In each category, rank them from strictly-structured to
     124             :  * loosely-structured.
     125             :  */
     126     7173598 : int getFlatTypeRank(const OUString& rType)
     127             : {
     128             :     // List formats from more complex to less complex.
     129             :     // TODO: Add more.
     130             :     static const char* ranks[] = {
     131             : 
     132             :         // Compressed XML (ODF XML zip formats)
     133             :         "writer8_template",
     134             :         "writer8",
     135             :         "calc8_template",
     136             :         "calc8",
     137             :         "impress8_template",
     138             :         "impress8",
     139             :         "draw8_template",
     140             :         "draw8",
     141             :         "chart8",
     142             :         "math8",
     143             :         "writerglobal8_template",
     144             :         "writerglobal8",
     145             :         "writerweb8_writer_template",
     146             :         "StarBase",
     147             : 
     148             :         // Compressed XML (OOXML)
     149             :         "writer_OOXML_Text_Template",
     150             :         "writer_OOXML",
     151             :         "writer_MS_Word_2007_Template",
     152             :         "writer_MS_Word_2007",
     153             :         "Office Open XML Spreadsheet Template",
     154             :         "Office Open XML Spreadsheet",
     155             :         "MS Excel 2007 XML Template",
     156             :         "MS Excel 2007 XML",
     157             :         "MS PowerPoint 2007 XML Template",
     158             :         "MS PowerPoint 2007 XML AutoPlay",
     159             :         "MS PowerPoint 2007 XML",
     160             : 
     161             :         // Compressed XML (Uniform/Unified Office Format)
     162             :         "Unified_Office_Format_text",
     163             :         "Unified_Office_Format_spreadsheet",
     164             :         "Unified_Office_Format_presentation",
     165             : 
     166             :         // Compressed XML (StarOffice XML zip formats)
     167             :         "calc_StarOffice_XML_Calc",
     168             :         "calc_StarOffice_XML_Calc_Template",
     169             :         "chart_StarOffice_XML_Chart",
     170             :         "draw_StarOffice_XML_Draw",
     171             :         "draw_StarOffice_XML_Draw_Template",
     172             :         "impress_StarOffice_XML_Impress",
     173             :         "impress_StarOffice_XML_Impress_Template",
     174             :         "math_StarOffice_XML_Math",
     175             :         "writer_StarOffice_XML_Writer",
     176             :         "writer_StarOffice_XML_Writer_Template",
     177             :         "writer_globaldocument_StarOffice_XML_Writer_GlobalDocument",
     178             :         "writer_web_StarOffice_XML_Writer_Web_Template",
     179             : 
     180             :         // Compressed text
     181             :         "pdf_Portable_Document_Format",
     182             : 
     183             :         // Binary
     184             :         "writer_T602_Document",
     185             :         "writer_WordPerfect_Document",
     186             :         "writer_MS_Works_Document",
     187             :         "writer_MS_Word_97_Vorlage",
     188             :         "writer_MS_Word_97",
     189             :         "writer_MS_Word_95_Vorlage",
     190             :         "writer_MS_Word_95",
     191             :         "writer_MS_WinWord_60",
     192             :         "writer_MS_WinWord_5",
     193             :         "MS Excel 2007 Binary",
     194             :         "calc_MS_Excel_97_VorlageTemplate",
     195             :         "calc_MS_Excel_97",
     196             :         "calc_MS_Excel_95_VorlageTemplate",
     197             :         "calc_MS_Excel_95",
     198             :         "calc_MS_Excel_5095_VorlageTemplate",
     199             :         "calc_MS_Excel_5095",
     200             :         "calc_MS_Excel_40_VorlageTemplate",
     201             :         "calc_MS_Excel_40",
     202             :         "calc_Pocket_Excel_File",
     203             :         "impress_MS_PowerPoint_97_Vorlage",
     204             :         "impress_MS_PowerPoint_97_AutoPlay",
     205             :         "impress_MS_PowerPoint_97",
     206             :         "calc_Lotus",
     207             :         "calc_QPro",
     208             :         "calc_SYLK",
     209             :         "calc_DIF",
     210             :         "calc_dBase",
     211             : 
     212             :         // Binary (raster and vector image files)
     213             :         "emf_MS_Windows_Metafile",
     214             :         "wmf_MS_Windows_Metafile",
     215             :         "met_OS2_Metafile",
     216             :         "svm_StarView_Metafile",
     217             :         "sgv_StarDraw_20",
     218             :         "tif_Tag_Image_File",
     219             :         "tga_Truevision_TARGA",
     220             :         "sgf_StarOffice_Writer_SGF",
     221             :         "ras_Sun_Rasterfile",
     222             :         "psd_Adobe_Photoshop",
     223             :         "png_Portable_Network_Graphic",
     224             :         "jpg_JPEG",
     225             :         "mov_MOV",
     226             :         "gif_Graphics_Interchange",
     227             :         "bmp_MS_Windows",
     228             :         "pcx_Zsoft_Paintbrush",
     229             :         "pct_Mac_Pict",
     230             :         "pcd_Photo_CD_Base",
     231             :         "pcd_Photo_CD_Base4",
     232             :         "pcd_Photo_CD_Base16",
     233             :         "impress_CGM_Computer_Graphics_Metafile", // There is binary and ascii variants ?
     234             :         "draw_WordPerfect_Graphics",
     235             :         "draw_Visio_Document",
     236             :         "draw_Publisher_Document",
     237             :         "draw_Corel_Presentation_Exchange",
     238             :         "draw_CorelDraw_Document",
     239             :         "writer_LotusWordPro_Document",
     240             :         "writer_MIZI_Hwp_97", // Hanword (Hancom Office)
     241             : 
     242             :         // Non-compressed XML
     243             :         "writer_ODT_FlatXML",
     244             :         "calc_ODS_FlatXML",
     245             :         "impress_ODP_FlatXML",
     246             :         "draw_ODG_FlatXML",
     247             :         "calc_MS_Excel_2003_XML",
     248             :         "writer_MS_Word_2003_XML",
     249             :         "writer_DocBook_File",
     250             :         "XHTML_File",
     251             :         "svg_Scalable_Vector_Graphics",
     252             :         "math_MathML_XML_Math",
     253             : 
     254             :         // Non-compressed text
     255             :         "dxf_AutoCAD_Interchange",
     256             :         "eps_Encapsulated_PostScript",
     257             :         "pbm_Portable_Bitmap",   // There is 'raw' and 'ascii' variants.
     258             :         "ppm_Portable_Pixelmap", // There is 'raw' and 'ascii' variants.
     259             :         "pgm_Portable_Graymap",  // There is 'raw' and 'ascii' variants.
     260             :         "xpm_XPM",
     261             :         "xbm_X_Consortium",
     262             :         "writer_Rich_Text_Format",
     263             :         "writer_web_HTML_help",
     264             :         "generic_HTML",
     265             : 
     266             :         "generic_Text", // Plain text (catch all)
     267             : 
     268             :         // Anything ranked lower than generic_Text will never be used during
     269             :         // type detection (since generic_Text catches all).
     270             : 
     271             :         // Export only
     272             :         "writer_layout_dump_xml",
     273             :         "pwp_PlaceWare",
     274             :         "graphic_SWF",
     275             :         "graphic_HTML",
     276             : 
     277             :         // Internal use only
     278             :         "StarBaseReportChart",
     279             :         "StarBaseReport",
     280             :         "math_MathType_3x", // MathType equation embedded in Word doc.
     281             :     };
     282             : 
     283     7173598 :     size_t n = SAL_N_ELEMENTS(ranks);
     284             : 
     285   555542401 :     for (size_t i = 0; i < n; ++i)
     286             :     {
     287   553453163 :         if (rType.equalsAscii(ranks[i]))
     288     5084360 :             return n - i - 1;
     289             :     }
     290             : 
     291             :     // Not ranked.  Treat them equally.  Unranked formats have higher priority
     292             :     // than the ranked internal ones since they may be defined externally.
     293     2089238 :     return n;
     294             : }
     295             : 
     296             : /**
     297             :  * Types with matching pattern first, then extension, then custom ranks by
     298             :  * types, then types that are supported by the document service come next.
     299             :  * Lastly, sort them alphabetically.
     300             :  */
     301             : struct SortByPriority : public std::binary_function<FlatDetectionInfo, FlatDetectionInfo, bool>
     302             : {
     303     3619462 :     bool operator() (const FlatDetectionInfo& r1, const FlatDetectionInfo& r2) const
     304             :     {
     305     3619462 :         if (r1.bMatchByPattern != r2.bMatchByPattern)
     306        5466 :             return r1.bMatchByPattern;
     307             : 
     308     3613996 :         if (r1.bMatchByExtension != r2.bMatchByExtension)
     309       27197 :             return r1.bMatchByExtension;
     310             : 
     311     3586799 :         int rank1 = getFlatTypeRank(r1.sType);
     312     3586799 :         int rank2 = getFlatTypeRank(r2.sType);
     313             : 
     314     3586799 :         if (rank1 != rank2)
     315     2892172 :             return rank1 > rank2;
     316             : 
     317      694627 :         if (r1.bPreselectedByDocumentService != r2.bPreselectedByDocumentService)
     318      157927 :             return r1.bPreselectedByDocumentService;
     319             : 
     320             :         // All things being equal, sort them alphabetically.
     321      536700 :         return r1.sType > r2.sType;
     322             :     }
     323             : };
     324             : 
     325             : struct SortByType : public std::binary_function<FlatDetectionInfo, FlatDetectionInfo, bool>
     326             : 
     327             : {
     328     5488062 :     bool operator() (const FlatDetectionInfo& r1, const FlatDetectionInfo& r2) const
     329             :     {
     330     5488062 :         return r1.sType > r2.sType;
     331             :     }
     332             : };
     333             : 
     334             : struct EqualByType : public std::binary_function<FlatDetectionInfo, FlatDetectionInfo, bool>
     335             : {
     336     1405352 :     bool operator() (const FlatDetectionInfo& r1, const FlatDetectionInfo& r2) const
     337             :     {
     338     1405352 :         return r1.sType == r2.sType;
     339             :     }
     340             : };
     341             : 
     342      495867 : class FindByType : std::unary_function<FlatDetectionInfo, bool>
     343             : {
     344             :     OUString maType;
     345             : public:
     346      165289 :     FindByType(const OUString& rType) : maType(rType) {}
     347     8891562 :     bool operator() (const FlatDetectionInfo& rInfo) const
     348             :     {
     349     8891562 :         return rInfo.sType == maType;
     350             :     }
     351             : };
     352             : 
     353             : #if DEBUG_TYPE_DETECTION
     354             : void printFlatDetectionList(const char* caption, const FlatDetection& types)
     355             : {
     356             :     cout << "-- " << caption << " (size=" << types.size() << ")" << endl;
     357             :     FlatDetection::const_iterator it = types.begin(), itEnd = types.end();
     358             :     for (; it != itEnd; ++it)
     359             :     {
     360             :         const FlatDetectionInfo& item = *it;
     361             :         cout << "  type='" << item.sType << "'; match by extension (" << item.bMatchByExtension
     362             :             << "); match by pattern (" << item.bMatchByPattern << "); pre-selected by doc service ("
     363             :             << item.bPreselectedByDocumentService << ")" << endl;
     364             :     }
     365             :     cout << "--" << endl;
     366             : }
     367             : #endif
     368             : 
     369             : }
     370             : 
     371        3253 : OUString SAL_CALL TypeDetection::queryTypeByDescriptor(css::uno::Sequence< css::beans::PropertyValue >& lDescriptor,
     372             :                                                               sal_Bool                                         bAllowDeep )
     373             :     throw (css::uno::RuntimeException, std::exception)
     374             : {
     375             :     // make the descriptor more useable :-)
     376        3253 :     utl::MediaDescriptor stlDescriptor(lDescriptor);
     377        6506 :     OUString sType, sURL;
     378             : 
     379             :     try
     380             :     {
     381             :         // SAFE -> ----------------------------------
     382        3253 :         ::osl::ResettableMutexGuard aLock(m_aLock);
     383             : 
     384             :         // parse given URL to split it into e.g. main and jump marks ...
     385        3253 :         sURL = stlDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_URL(), OUString());
     386             : 
     387             : #if OSL_DEBUG_LEVEL > 0
     388             :         if (stlDescriptor.find( "FileName" ) != stlDescriptor.end())
     389             :             OSL_FAIL("Detect using of deprecated and already unsupported MediaDescriptor property \"FileName\"!");
     390             : #endif
     391             : 
     392        6506 :         css::util::URL  aURL;
     393        3253 :         aURL.Complete = sURL;
     394        6506 :         css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
     395        3253 :         xParser->parseStrict(aURL);
     396             : 
     397             :         OUString aSelectedFilter = stlDescriptor.getUnpackedValueOrDefault(
     398        6506 :             utl::MediaDescriptor::PROP_FILTERNAME(), OUString());
     399        3253 :         if (!aSelectedFilter.isEmpty())
     400             :         {
     401             :             // Caller specified the filter type.  Honor it.  Just get the default
     402             :             // type for that filter, and bail out.
     403           0 :             if (impl_validateAndSetFilterOnDescriptor(stlDescriptor, aSelectedFilter))
     404           0 :                 return stlDescriptor[utl::MediaDescriptor::PROP_TYPENAME()].get<OUString>();
     405             :         }
     406             : 
     407        6506 :         FlatDetection lFlatTypes;
     408        3253 :         impl_getAllFormatTypes(aURL, stlDescriptor, lFlatTypes);
     409             : 
     410        3253 :         aLock.clear();
     411             :         // <- SAFE ----------------------------------
     412             : 
     413             :         // Properly prioritize all candidate types.
     414        3253 :         lFlatTypes.sort(SortByPriority());
     415        3253 :         lFlatTypes.unique(EqualByType());
     416             : 
     417        6506 :         OUString sLastChance;
     418             : 
     419             :         // verify every flat detected (or preselected!) type
     420             :         // by calling its registered deep detection service.
     421             :         // But break this loop if a type match to the given descriptor
     422             :         // by an URL pattern(!) or if deep detection isn't allowed from
     423             :         // outside (bAllowDeep=sal_False) or break the whole detection by
     424             :         // throwing an exception if creation of the might needed input
     425             :         // stream failed by e.g. an IO exception ...
     426        6506 :         OUStringList lUsedDetectors;
     427        3253 :         if (lFlatTypes.size()>0)
     428        3253 :             sType = impl_detectTypeFlatAndDeep(stlDescriptor, lFlatTypes, bAllowDeep, lUsedDetectors, sLastChance);
     429             : 
     430             : 
     431             :         // flat detection failed
     432             :         // pure deep detection failed
     433             :         // => ask might existing InteractionHandler
     434             :         // means: ask user for it's decision
     435        3252 :         if (sType.isEmpty())
     436          15 :             sType = impl_askUserForTypeAndFilterIfAllowed(stlDescriptor);
     437             : 
     438             : 
     439             :         // no real detected type - but a might valid one.
     440             :         // update descriptor and set last chance for return.
     441        3252 :         if (sType.isEmpty() && !sLastChance.isEmpty())
     442             :         {
     443             :             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!");
     444          15 :             sType = sLastChance;
     445        3253 :         }
     446             :     }
     447           0 :     catch(const css::uno::RuntimeException&)
     448             :     {
     449           0 :         throw;
     450             :     }
     451           2 :     catch(const css::uno::Exception& e)
     452             :     {
     453             :         SAL_WARN(
     454             :             "filter.config",
     455             :             "caught Exception \"" << e.Message
     456             :                 << "\" while querying type of <" << sURL << ">");
     457           1 :         sType.clear();
     458             :     }
     459             : 
     460             :     // adapt media descriptor, so it contains the right values
     461             :     // for type/filter name/document service/ etcpp.
     462        3253 :     impl_checkResultsAndAddBestFilter(stlDescriptor, sType); // Attention: sType is used as IN/OUT param here and will might be changed inside this method !!!
     463        3253 :     impl_validateAndSetTypeOnDescriptor(stlDescriptor, sType);
     464             : 
     465        3253 :     stlDescriptor >> lDescriptor;
     466        6506 :     return sType;
     467             : }
     468             : 
     469             : 
     470             : 
     471        3253 : void TypeDetection::impl_checkResultsAndAddBestFilter(utl::MediaDescriptor& rDescriptor,
     472             :                                                       OUString&               sType      )
     473             : {
     474             :     // a)
     475             :     // Dont overwrite a might preselected filter!
     476             :     OUString sFilter = rDescriptor.getUnpackedValueOrDefault(
     477        3253 :                                 utl::MediaDescriptor::PROP_FILTERNAME(),
     478        6506 :                                 OUString());
     479        3253 :     if (!sFilter.isEmpty())
     480          43 :         return;
     481             : 
     482             :     // b)
     483             :     // check a preselected document service too.
     484             :     // Then we have to search a suitable filter witin this module.
     485             :     OUString sDocumentService = rDescriptor.getUnpackedValueOrDefault(
     486        3210 :                                             utl::MediaDescriptor::PROP_DOCUMENTSERVICE(),
     487        6437 :                                             OUString());
     488        3210 :     if (!sDocumentService.isEmpty())
     489             :     {
     490             :         try
     491             :         {
     492        2388 :             OUString sRealType = sType;
     493             : 
     494             :             // SAFE ->
     495        2393 :             ::osl::ResettableMutexGuard aLock(m_aLock);
     496             : 
     497             :             // Attention: For executing next lines of code, We must be sure that
     498             :             // all filters already loaded :-(
     499             :             // That can disturb our "load on demand feature". But we have no other chance!
     500        2388 :             m_rCache->load(FilterCache::E_CONTAINS_FILTERS);
     501             : 
     502        2393 :             CacheItem lIProps;
     503        2388 :             lIProps[PROPNAME_DOCUMENTSERVICE] <<= sDocumentService;
     504        2388 :             lIProps[PROPNAME_TYPE           ] <<= sRealType;
     505        2393 :             OUStringList lFilters = m_rCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps);
     506             : 
     507        2388 :             aLock.clear();
     508             :             // <- SAFE
     509             : 
     510       11922 :             for (OUStringList::const_iterator pIt  = lFilters.begin();
     511        7948 :                   pIt != lFilters.end(); ++pIt)
     512             :             {
     513             :                 // SAFE ->
     514        2384 :                 aLock.reset();
     515             :                 try
     516             :                 {
     517        2384 :                     CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, *pIt);
     518        2384 :                     sal_Int32 nFlags  = 0;
     519        2384 :                     aFilter[PROPNAME_FLAGS] >>= nFlags;
     520             : 
     521        2384 :                     if ((nFlags & FLAGVAL_IMPORT) == FLAGVAL_IMPORT)
     522        2383 :                         sFilter = *pIt;
     523        2384 :                     if ((nFlags & FLAGVAL_PREFERRED) == FLAGVAL_PREFERRED)
     524         798 :                         break;
     525             :                 }
     526           0 :                 catch(const css::uno::Exception&) {}
     527        1586 :                 aLock.clear();
     528             :                 // <- SAFE
     529             :             }
     530             : 
     531        2388 :             if (!sFilter.isEmpty())
     532             :             {
     533        2383 :                 rDescriptor[utl::MediaDescriptor::PROP_TYPENAME()  ] <<= sRealType;
     534        2383 :                 rDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
     535        2383 :                 sType = sRealType;
     536        2383 :                 return;
     537           5 :             }
     538             :         }
     539           0 :         catch(const css::uno::Exception&)
     540             :             {}
     541             :     }
     542             : 
     543             :     // c)
     544             :     // We can use the preferred filter for the specified type.
     545             :     // Such preferred filter points:
     546             :     // - to the default filter of the preferred application
     547             :     // - or to any other filter if no preferred filter was set.
     548             :     // Note: It's an optimization only!
     549             :     // It's not guaranteed, that such preferred filter exists.
     550         827 :     sFilter.clear();
     551             :     try
     552             :     {
     553             :         // SAFE ->
     554         827 :         ::osl::ResettableMutexGuard aLock(m_aLock);
     555             : 
     556        1653 :         CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sType);
     557         826 :         aType[PROPNAME_PREFERREDFILTER] >>= sFilter;
     558        1636 :         CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter);
     559             : 
     560         810 :         aLock.clear();
     561             :         // <- SAFE
     562             : 
     563             :         // no exception => found valid type and filter => set it on the given descriptor
     564         810 :         rDescriptor[utl::MediaDescriptor::PROP_TYPENAME()  ] <<= sType  ;
     565         810 :         rDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
     566        1637 :         return;
     567             :     }
     568          17 :     catch(const css::uno::Exception&)
     569             :         {}
     570             : 
     571             :     // d)
     572             :     // Search for any import(!) filter, which is registered for this type.
     573          17 :     sFilter.clear();
     574             :     try
     575             :     {
     576             :         // SAFE ->
     577          17 :         ::osl::ResettableMutexGuard aLock(m_aLock);
     578             : 
     579             :         // Attention: For executing next lines of code, We must be sure that
     580             :         // all filters already loaded :-(
     581             :         // That can disturb our "load on demand feature". But we have no other chance!
     582          17 :         m_rCache->load(FilterCache::E_CONTAINS_FILTERS);
     583             : 
     584          34 :         CacheItem lIProps;
     585          17 :         lIProps[PROPNAME_TYPE] <<= sType;
     586          34 :         OUStringList lFilters = m_rCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps);
     587             : 
     588          17 :         aLock.clear();
     589             :         // <- SAFE
     590             : 
     591          17 :         OUStringList::const_iterator pIt;
     592          96 :         for (  pIt  = lFilters.begin();
     593          64 :                pIt != lFilters.end()  ;
     594             :              ++pIt                    )
     595             :         {
     596          15 :             sFilter = *pIt;
     597             : 
     598             :             // SAFE ->
     599          15 :             aLock.reset();
     600             :             try
     601             :             {
     602          15 :                 CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter);
     603          15 :                 sal_Int32 nFlags  = 0;
     604          15 :                 aFilter[PROPNAME_FLAGS] >>= nFlags;
     605             : 
     606          15 :                 if ((nFlags & FLAGVAL_IMPORT) == FLAGVAL_IMPORT)
     607           0 :                     break;
     608             :             }
     609           0 :             catch(const css::uno::Exception&)
     610           0 :                 { continue; }
     611          15 :             aLock.clear();
     612             :             // <- SAFE
     613             : 
     614          15 :             sFilter.clear();
     615             :         }
     616             : 
     617          17 :         if (!sFilter.isEmpty())
     618             :         {
     619           0 :             rDescriptor[utl::MediaDescriptor::PROP_TYPENAME()  ] <<= sType  ;
     620           0 :             rDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
     621           0 :             return;
     622          17 :         }
     623             :     }
     624           0 :     catch(const css::uno::Exception&)
     625          17 :         {}
     626             : }
     627             : 
     628             : 
     629             : 
     630      160809 : bool TypeDetection::impl_getPreselectionForType(
     631             :     const OUString& sPreSelType, const util::URL& aParsedURL, FlatDetection& rFlatTypes, bool bDocService)
     632             : {
     633             :     // Can be used to suppress execution of some parts of this method
     634             :     // if its already clear that detected type is valid or not.
     635             :     // Its necessary to use shared code at the end, which update
     636             :     // all return parameters constistency!
     637      160809 :     bool bBreakDetection = false;
     638             : 
     639             :     // Further we must know if it matches by pattern
     640             :     // Every flat detected type by pattern wont be detected deep!
     641      160809 :     bool bMatchByPattern = false;
     642             : 
     643             :     // And we must know if a preselection must be preferred, because
     644             :     // it matches by it's extension too.
     645      160809 :     bool bMatchByExtension = false;
     646             : 
     647             :     // validate type
     648      160809 :     OUString sType(sPreSelType);
     649      321618 :     CacheItem       aType;
     650             :     try
     651             :     {
     652             :         // SAFE -> --------------------------
     653      160809 :         ::osl::ResettableMutexGuard aLock(m_aLock);
     654      160809 :         aType = m_rCache->getItem(FilterCache::E_TYPE, sType);
     655      160809 :         aLock.clear();
     656             :         // <- SAFE --------------------------
     657             :     }
     658           0 :     catch(const css::container::NoSuchElementException&)
     659             :     {
     660           0 :         sType.clear();
     661           0 :         bBreakDetection = true;
     662             :     }
     663             : 
     664      160809 :     if (!bBreakDetection)
     665             :     {
     666             :         // We can't check a preselected type for a given stream!
     667             :         // So we must believe, that it can work ...
     668      160809 :         if ( aParsedURL.Complete == "private:stream" )
     669           0 :             bBreakDetection = true;
     670             :     }
     671             : 
     672      160809 :     if (!bBreakDetection)
     673             :     {
     674             :         // extract extension from URL .. to check it case-insensitive !
     675      160809 :         INetURLObject   aParser    (aParsedURL.Main);
     676             :         OUString sExtension = aParser.getExtension(INetURLObject::LAST_SEGMENT       ,
     677             :                                                           true                          ,
     678      321618 :                                                           INetURLObject::DECODE_WITH_CHARSET);
     679      160809 :         sExtension = sExtension.toAsciiLowerCase();
     680             : 
     681             :         // otherwise we must know, if it matches to the given URL really.
     682             :         // especially if it matches by its extension or pattern registration.
     683      321618 :         OUStringList lExtensions(comphelper::sequenceToContainer<OUStringList>(aType[PROPNAME_EXTENSIONS].get<css::uno::Sequence<OUString> >() ));
     684      321618 :         OUStringList lURLPattern(comphelper::sequenceToContainer<OUStringList>(aType[PROPNAME_URLPATTERN].get<css::uno::Sequence<OUString> >() ));
     685             : 
     686     1192008 :         for (OUStringList::const_iterator pIt  = lExtensions.begin();
     687      794672 :                                           pIt != lExtensions.end()  ;
     688             :                                         ++pIt                       )
     689             :         {
     690      240056 :             OUString sCheckExtension(pIt->toAsciiLowerCase());
     691      240056 :             if (sCheckExtension.equals(sExtension))
     692             :             {
     693        3529 :                 bBreakDetection        = true;
     694        3529 :                 bMatchByExtension      = true;
     695        3529 :                 break;
     696             :             }
     697      236527 :         }
     698             : 
     699      160809 :         if (!bBreakDetection)
     700             :         {
     701      485967 :             for (OUStringList::const_iterator pIt  = lURLPattern.begin();
     702      323978 :                                               pIt != lURLPattern.end()  ;
     703             :                                             ++pIt                       )
     704             :             {
     705        4710 :                 WildCard aCheck(*pIt);
     706        4710 :                 if (aCheck.Matches(aParsedURL.Main))
     707             :                 {
     708           1 :                     bMatchByPattern        = true;
     709           1 :                     break;
     710             :                 }
     711        4709 :             }
     712      160809 :         }
     713             :     }
     714             : 
     715             :     // if it's a valid type - set it on all return values!
     716      160809 :     if (!sType.isEmpty())
     717             :     {
     718      160809 :         FlatDetection::iterator it = std::find_if(rFlatTypes.begin(), rFlatTypes.end(), FindByType(sType));
     719      160809 :         if (it != rFlatTypes.end())
     720             :         {
     721      160809 :             if (bMatchByExtension)
     722        3529 :                 it->bMatchByExtension = true;
     723      160809 :             if (bMatchByPattern)
     724           1 :                 it->bMatchByPattern = true;
     725      160809 :             if (bDocService)
     726      160809 :                 it->bPreselectedByDocumentService = true;
     727             :         }
     728             : 
     729      160809 :         return true;
     730             :     }
     731             : 
     732             :     // not valid!
     733      160809 :     return false;
     734             : }
     735             : 
     736        2425 : 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        2425 :     OUStringList lFilters;
     741             :     try
     742             :     {
     743             :         // SAFE -> --------------------------
     744        2425 :         ::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        2425 :         m_rCache->load(FilterCache::E_CONTAINS_FILTERS);
     750             : 
     751        4850 :         CacheItem lIProps;
     752        2425 :         lIProps[PROPNAME_DOCUMENTSERVICE] <<= sPreSelDocumentService;
     753        2425 :         lFilters = m_rCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps);
     754             : 
     755        4850 :         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      489702 :     for (OUStringList::const_iterator pFilter  = lFilters.begin();
     769      326468 :          pFilter != lFilters.end();
     770             :          ++pFilter)
     771             :     {
     772      160809 :         OUString aType = impl_getTypeFromFilter(*pFilter);
     773      160809 :         if (aType.isEmpty())
     774           0 :             continue;
     775             : 
     776      160809 :         impl_getPreselectionForType(aType, aParsedURL, rFlatTypes, true);
     777      160809 :     }
     778             : 
     779        2425 :     return true;
     780             : }
     781             : 
     782      980565 : OUString TypeDetection::impl_getTypeFromFilter(const OUString& rFilterName)
     783             : {
     784      980565 :     CacheItem aFilter;
     785             :     try
     786             :     {
     787      980565 :         osl::MutexGuard aLock(m_aLock);
     788      980565 :         aFilter = m_rCache->getItem(FilterCache::E_FILTER, rFilterName);
     789             :     }
     790           0 :     catch (const container::NoSuchElementException&)
     791             :     {
     792           0 :         return OUString();
     793             :     }
     794             : 
     795     1961130 :     OUString aType;
     796      980565 :     aFilter[PROPNAME_TYPE] >>= aType;
     797     1961130 :     return aType;
     798             : }
     799             : 
     800        3253 : void TypeDetection::impl_getAllFormatTypes(
     801             :     const util::URL& aParsedURL, utl::MediaDescriptor& rDescriptor, FlatDetection& rFlatTypes)
     802             : {
     803        3253 :     rFlatTypes.clear();
     804             : 
     805             :     // Get all filters that we have.
     806        3253 :     OUStringList aFilterNames;
     807             :     try
     808             :     {
     809        3253 :         osl::MutexGuard aLock(m_aLock);
     810        3253 :         m_rCache->load(FilterCache::E_CONTAINS_FILTERS);
     811        3253 :         aFilterNames = m_rCache->getItemNames(FilterCache::E_FILTER);
     812             :     }
     813           0 :     catch (const container::NoSuchElementException&)
     814             :     {
     815        3253 :         return;
     816             :     }
     817             : 
     818             :     // Retrieve the default type for each of these filters, and store them.
     819      823009 :     for (OUStringList::const_iterator it = aFilterNames.begin(); it != aFilterNames.end(); ++it)
     820             :     {
     821      819756 :         OUString aType = impl_getTypeFromFilter(*it);
     822             : 
     823      819756 :         if (aType.isEmpty())
     824           0 :             continue;
     825             : 
     826     1639512 :         FlatDetectionInfo aInfo; // all flags set to false by default.
     827      819756 :         aInfo.sType = aType;
     828      819756 :         rFlatTypes.push_back(aInfo);
     829      819756 :     }
     830             : 
     831             :     {
     832             :         // Get all types that match the URL alone.
     833        3253 :         FlatDetection aFlatByURL;
     834        3253 :         m_rCache->detectFlatForURL(aParsedURL, aFlatByURL);
     835        3253 :         FlatDetection::const_iterator it = aFlatByURL.begin(), itEnd = aFlatByURL.end();
     836        7733 :         for (; it != itEnd; ++it)
     837             :         {
     838        4480 :             FlatDetection::iterator itPos = std::find_if(rFlatTypes.begin(), rFlatTypes.end(), FindByType(it->sType));
     839        4480 :             if (itPos == rFlatTypes.end())
     840             :                 // Not in the list yet.
     841          28 :                 rFlatTypes.push_back(*it);
     842             :             else
     843             :             {
     844             :                 // Already in the list. Update the flags.
     845        4452 :                 FlatDetectionInfo& rInfo = *itPos;
     846        4452 :                 const FlatDetectionInfo& rThisInfo = *it;
     847        4452 :                 if (rThisInfo.bMatchByExtension)
     848        3734 :                     rInfo.bMatchByExtension = true;
     849        4452 :                 if (rThisInfo.bMatchByPattern)
     850         718 :                     rInfo.bMatchByPattern = true;
     851        4452 :                 if (rThisInfo.bPreselectedByDocumentService)
     852           0 :                     rInfo.bPreselectedByDocumentService = true;
     853             :             }
     854        3253 :         }
     855             :     }
     856             : 
     857             :     // Remove duplicates.
     858        3253 :     rFlatTypes.sort(SortByType());
     859        3253 :     rFlatTypes.unique(EqualByType());
     860             : 
     861             :     // Mark pre-selected type (if any) to have it prioritized.
     862        6506 :     OUString sSelectedType = rDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME(), OUString());
     863        3253 :     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        6506 :     OUString sSelectedDoc = rDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_DOCUMENTSERVICE(), OUString());
     868        3253 :     if (!sSelectedDoc.isEmpty())
     869        5678 :         impl_getPreselectionForDocumentService(sSelectedDoc, aParsedURL, rFlatTypes);
     870             : }
     871             : 
     872             : 
     873             : 
     874        3253 : 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        3253 :     rLastChance.clear();
     883        3253 :     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      171924 :     for (FlatDetection::const_iterator pFlatIt  = lFlatTypes.begin();
     901      114616 :                                        pFlatIt != lFlatTypes.end()  ;
     902             :                                      ++pFlatIt                      )
     903             :     {
     904       57293 :         const FlatDetectionInfo& aFlatTypeInfo = *pFlatIt;
     905       57293 :         OUString sFlatType = aFlatTypeInfo.sType;
     906             : 
     907       57293 :         if (!impl_validateAndSetTypeOnDescriptor(rDescriptor, sFlatType))
     908           0 :             continue;
     909             : 
     910             :         // b)
     911       57293 :         if (
     912      114586 :             (!bAllowDeep                  ) ||
     913             :             (aFlatTypeInfo.bMatchByPattern)
     914             :            )
     915             :         {
     916         719 :             return sFlatType;
     917             :         }
     918             : 
     919             :         try
     920             :         {
     921             :             // SAFE -> ----------------------------------
     922       56574 :             ::osl::ResettableMutexGuard aLock(m_aLock);
     923      110570 :             CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sFlatType);
     924       56574 :             aLock.clear();
     925             : 
     926      110570 :             OUString sDetectService;
     927       56574 :             aType[PROPNAME_DETECTSERVICE] >>= sDetectService;
     928             : 
     929             :             // c)
     930       56574 :             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          60 :                 if (rLastChance.isEmpty())
     937          15 :                     rLastChance = sFlatType;
     938             : 
     939          60 :                 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       56514 :             rUsedDetectors.push_back(sDetectService);
     946      110509 :             OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor);
     947             : 
     948             :             // d)
     949       56513 :             if (!sDeepType.isEmpty())
     950       56514 :                 return sDeepType;
     951             :         }
     952           0 :         catch(const css::container::NoSuchElementException&)
     953             :             {}
     954             :         // e)
     955       53996 :     }
     956             : 
     957          15 :     return OUString();
     958             :     // <- SAFE ----------------------------------
     959             : }
     960             : 
     961       75764 : 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       75764 :                                                             utl::MediaDescriptor::PROP_INPUTSTREAM(),
     967      151528 :                                                             css::uno::Reference< css::io::XInputStream >());
     968      151528 :     css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY);
     969       75764 :     if (xSeek.is())
     970             :     {
     971             :         try
     972             :         {
     973       75757 :             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       75764 :     }
     983       75764 : }
     984             : 
     985       56514 : 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       56514 :     impl_openStream(rDescriptor);
     994             : 
     995             :     // seek to 0 is an optional feature to be more robust against
     996             :     // "simple implemented detect services" .-)
     997       56513 :     impl_seekStreamToZero(rDescriptor);
     998             : 
     999       56513 :     css::uno::Reference< css::document::XExtendedFilterDetection > xDetector;
    1000      113026 :     css::uno::Reference< css::uno::XComponentContext >         xContext;
    1001             : 
    1002             :     // SAFE ->
    1003      113026 :     ::osl::ResettableMutexGuard aLock(m_aLock);
    1004       56513 :     xContext = m_xContext;
    1005       56513 :     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       75764 :         xDetector = css::uno::Reference< css::document::XExtendedFilterDetection >(
    1017      113026 :                 xContext->getServiceManager()->createInstanceWithContext(sDetectService, xContext),
    1018       19251 :                 css::uno::UNO_QUERY_THROW);
    1019             :     }
    1020       37262 :     catch (...)
    1021             :     {
    1022             :     }
    1023             : 
    1024       56513 :     if ( ! xDetector.is())
    1025       37262 :         return OUString();
    1026             : 
    1027       38502 :     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       19251 :         css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
    1039       19251 :         rDescriptor >> lDescriptor;
    1040       19251 :         sDeepType = xDetector->detect(lDescriptor);
    1041       19251 :         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.clear();
    1050             :         }
    1051             : 
    1052             :     // seek to 0 is an optional feature to be more robust against
    1053             :     // "simple implemented detect services" .-)
    1054       19251 :     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       19251 :     bool bValidType = impl_validateAndSetTypeOnDescriptor(rDescriptor, sDeepType);
    1064       19251 :     if (bValidType)
    1065        2518 :         return sDeepType;
    1066             : 
    1067       73246 :     return OUString();
    1068             : }
    1069             : 
    1070             : 
    1071             : 
    1072          15 : OUString TypeDetection::impl_askUserForTypeAndFilterIfAllowed(utl::MediaDescriptor& rDescriptor)
    1073             : {
    1074             :     css::uno::Reference< css::task::XInteractionHandler > xInteraction =
    1075          15 :         rDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_INTERACTIONHANDLER(),
    1076          30 :         css::uno::Reference< css::task::XInteractionHandler >());
    1077             : 
    1078          15 :     if (!xInteraction.is())
    1079          15 :         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". Especially 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          15 :     return OUString();
    1129             : }
    1130             : 
    1131             : 
    1132             : 
    1133       56514 : void TypeDetection::impl_openStream(utl::MediaDescriptor& rDescriptor)
    1134             :     throw (css::uno::Exception)
    1135             : {
    1136       56514 :     bool bSuccess = false;
    1137       56514 :     OUString sURL = rDescriptor.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_URL(), OUString() );
    1138       56514 :     bool bRequestedReadOnly = rDescriptor.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_READONLY(), false );
    1139       56514 :     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       55743 :         bSuccess = rDescriptor.addInputStreamOwnLock();
    1143             :     }
    1144             :     else
    1145         771 :         bSuccess = rDescriptor.addInputStream();
    1146             : 
    1147       56514 :     if ( !bSuccess )
    1148             :         throw css::uno::Exception(
    1149           2 :             "Could not open stream for <" + sURL + ">",
    1150           3 :             static_cast<OWeakObject *>(this));
    1151             : 
    1152       56513 :     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       56503 :         rDescriptor.erase( utl::MediaDescriptor::PROP_READONLY() );
    1159       56514 :     }
    1160       56513 : }
    1161             : 
    1162             : 
    1163             : 
    1164       16734 : void TypeDetection::impl_removeTypeFilterFromDescriptor(utl::MediaDescriptor& rDescriptor)
    1165             : {
    1166       16734 :     utl::MediaDescriptor::iterator pItType   = rDescriptor.find(utl::MediaDescriptor::PROP_TYPENAME()  );
    1167       16734 :     utl::MediaDescriptor::iterator pItFilter = rDescriptor.find(utl::MediaDescriptor::PROP_FILTERNAME());
    1168       16734 :     if (pItType != rDescriptor.end())
    1169       16734 :         rDescriptor.erase(pItType);
    1170       16734 :     if (pItFilter != rDescriptor.end())
    1171           0 :         rDescriptor.erase(pItFilter);
    1172       16734 : }
    1173             : 
    1174             : 
    1175             : 
    1176       79797 : bool TypeDetection::impl_validateAndSetTypeOnDescriptor(      utl::MediaDescriptor& rDescriptor,
    1177             :                                                             const OUString&               sType      )
    1178             : {
    1179             :     // SAFE ->
    1180       79797 :     ::osl::ResettableMutexGuard aLock(m_aLock);
    1181       79797 :     if (m_rCache->hasItem(FilterCache::E_TYPE, sType))
    1182             :     {
    1183       63063 :         rDescriptor[utl::MediaDescriptor::PROP_TYPENAME()] <<= sType;
    1184       63063 :         return true;
    1185             :     }
    1186       16734 :     aLock.clear();
    1187             :     // <- SAFE
    1188             : 
    1189             :     // remove all related information from the descriptor
    1190       16734 :     impl_removeTypeFilterFromDescriptor(rDescriptor);
    1191       16734 :     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       44716 : OUString TypeDetection::impl_getImplementationName()
    1227             : {
    1228       44716 :     return OUString( "com.sun.star.comp.filter.config.TypeDetection" );
    1229             : }
    1230             : 
    1231             : 
    1232             : 
    1233       44219 : css::uno::Sequence< OUString > TypeDetection::impl_getSupportedServiceNames()
    1234             : {
    1235       44219 :     css::uno::Sequence< OUString > lServiceNames(1);
    1236       44219 :     lServiceNames[0] = "com.sun.star.document.TypeDetection";
    1237       44219 :     return lServiceNames;
    1238             : }
    1239             : 
    1240             : 
    1241             : 
    1242       44102 : css::uno::Reference< css::uno::XInterface > SAL_CALL TypeDetection::impl_createInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
    1243             : {
    1244       44102 :     TypeDetection* pNew = new TypeDetection( comphelper::getComponentContext(xSMGR) );
    1245       44102 :     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.11