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

Generated by: LCOV version 1.10