| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_filter.hxx" |
| #include "typedetection.hxx" |
| #include "constant.hxx" |
| |
| //_______________________________________________ |
| // includes |
| #include <com/sun/star/document/XExtendedFilterDetection.hpp> |
| #include <com/sun/star/util/XURLTransformer.hpp> |
| |
| #ifndef _COM_SUN_STAR_IO_XINPUSTREAM_HPP_ |
| #include <com/sun/star/io/XInputStream.hpp> |
| #endif |
| #include <com/sun/star/io/XSeekable.hpp> |
| #include <com/sun/star/task/XInteractionHandler.hpp> |
| #include <tools/wldcrd.hxx> |
| #include <rtl/ustrbuf.hxx> |
| #include <framework/interaction.hxx> |
| #include <tools/urlobj.hxx> |
| #include <unotools/localfilehelper.hxx> |
| |
| //_______________________________________________ |
| // namespace |
| |
| namespace filter{ |
| namespace config{ |
| |
| namespace css = ::com::sun::star; |
| |
| //_______________________________________________ |
| // definitions |
| |
| // Use this switch to change the behaviour of preselection DocumentService ... (see using for further informations) |
| #define IGNORE_NON_URLMATCHING_TYPES_FOR_PRESELECTION_DOCUMENTSERVICE |
| |
| // enable/disable special handling for CSV/TXT problem |
| #define WORKAROUND_CSV_TXT_BUG_i60158 |
| |
| /*----------------------------------------------- |
| 03.07.2003 11:25 |
| -----------------------------------------------*/ |
| TypeDetection::TypeDetection(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR) |
| { |
| BaseContainer::init(xSMGR , |
| TypeDetection::impl_getImplementationName() , |
| TypeDetection::impl_getSupportedServiceNames(), |
| FilterCache::E_TYPE ); |
| } |
| |
| /*----------------------------------------------- |
| 03.07.2003 10:36 |
| -----------------------------------------------*/ |
| TypeDetection::~TypeDetection() |
| { |
| } |
| |
| /*----------------------------------------------- |
| 03.11.2003 08:43 |
| -----------------------------------------------*/ |
| ::rtl::OUString SAL_CALL TypeDetection::queryTypeByURL(const ::rtl::OUString& sURL) |
| throw (css::uno::RuntimeException) |
| { |
| ::rtl::OUString sType; |
| |
| // SAFE -> |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| |
| css::util::URL aURL; |
| aURL.Complete = sURL; |
| css::uno::Reference< css::util::XURLTransformer > xParser(m_xSMGR->createInstance(SERVICE_URLTRANSFORMER), css::uno::UNO_QUERY); |
| xParser->parseStrict(aURL); |
| |
| // set std types as minimum requirement first! |
| // Only in case no type was found for given URL, |
| // use optional types too ... |
| FlatDetection lFlatTypes; |
| m_rCache->detectFlatForURL(aURL, lFlatTypes); |
| |
| if ( |
| (lFlatTypes.size() < 1 ) && |
| (!m_rCache->isFillState(FilterCache::E_CONTAINS_TYPES)) |
| ) |
| { |
| m_rCache->load(FilterCache::E_CONTAINS_TYPES); |
| m_rCache->detectFlatForURL(aURL, lFlatTypes); |
| } |
| |
| // first item is guaranteed as "preferred" one! |
| if (lFlatTypes.size() > 0) |
| { |
| const FlatDetectionInfo& aMatch = *(lFlatTypes.begin()); |
| sType = aMatch.sType; |
| } |
| |
| return sType; |
| // <- SAFE |
| } |
| |
| /*----------------------------------------------- |
| 31.10.2003 09:36 |
| -----------------------------------------------*/ |
| ::rtl::OUString SAL_CALL TypeDetection::queryTypeByDescriptor(css::uno::Sequence< css::beans::PropertyValue >& lDescriptor, |
| sal_Bool bAllowDeep ) |
| throw (css::uno::RuntimeException) |
| { |
| // make the descriptor more useable :-) |
| ::comphelper::MediaDescriptor stlDescriptor(lDescriptor); |
| |
| // SAFE -> ---------------------------------- |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| |
| //******************************************* |
| // parse given URL to split it into e.g. main and jump marks ... |
| ::rtl::OUString sURL = stlDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_URL(), ::rtl::OUString()); |
| |
| #if OSL_DEBUG_LEVEL > 0 |
| if (stlDescriptor.find(::rtl::OUString::createFromAscii("FileName")) != stlDescriptor.end()) |
| OSL_ENSURE(sal_False, "Detect using of deprecated and already unsupported MediaDescriptor property \"FileName\"!"); |
| #endif |
| |
| css::util::URL aURL; |
| aURL.Complete = sURL; |
| css::uno::Reference< css::util::XURLTransformer > xParser(m_xSMGR->createInstance(SERVICE_URLTRANSFORMER), css::uno::UNO_QUERY); |
| xParser->parseStrict(aURL); |
| |
| //******************************************* |
| // preselected filter, type or document service? |
| // use it as first "flat" detected type later! |
| FlatDetection lFlatTypes; |
| impl_getPreselection(aURL, stlDescriptor, lFlatTypes); |
| |
| //******************************************* |
| // get all types, which match to the given descriptor |
| // That can be true by: extensions/url pattern/mime type etcpp. |
| m_rCache->detectFlatForURL(aURL, lFlatTypes); |
| |
| aLock.clear(); |
| // <- SAFE ---------------------------------- |
| |
| ::rtl::OUString sType ; |
| ::rtl::OUString sLastChance; |
| |
| try |
| { |
| //******************************************* |
| // verify every flat detected (or preselected!) type |
| // by calling its registered deep detection service. |
| // But break this loop if a type match to the given descriptor |
| // by an URL pattern(!) or if deep detection isnt allowed from |
| // outside (bAllowDeep=sal_False) or break the whole detection by |
| // throwing an exception if creation of the might needed input |
| // stream failed by e.g. an IO exception ... |
| OUStringList lUsedDetectors; |
| if (lFlatTypes.size()>0) |
| sType = impl_detectTypeFlatAndDeep(stlDescriptor, lFlatTypes, bAllowDeep, lUsedDetectors, sLastChance); |
| |
| //******************************************* |
| // if no flat detected (nor preselected!) type could be |
| // verified and no error occured during creation of |
| // the might needed input stream, start detection |
| // which uses all registered deep detection services. |
| if ( |
| (!sType.getLength()) && |
| (bAllowDeep ) |
| ) |
| { |
| sType = impl_detectTypeDeepOnly(stlDescriptor, lUsedDetectors); |
| } |
| |
| //******************************************* |
| // flat detection failed |
| // pure deep detection failed |
| // => ask might existing InteractionHandler |
| // means: ask user for it's decision |
| if (!sType.getLength()) |
| sType = impl_askUserForTypeAndFilterIfAllowed(stlDescriptor); |
| |
| //******************************************* |
| // no real detected type - but a might valid one. |
| // update descriptor and set last chance for return. |
| if (!sType.getLength() && sLastChance.getLength()) |
| { |
| OSL_ENSURE(sal_False, "set first flat detected type without a registered deep detection service as \"last chance\" ... nevertheless some other deep detections said \"NO\". I TRY IT!"); |
| sType = sLastChance; |
| } |
| } |
| catch(const css::uno::RuntimeException&) |
| { throw; } |
| catch(const css::uno::Exception&) |
| { sType = ::rtl::OUString(); } |
| |
| //******************************************* |
| // adapt media descriptor, so it contains the right values |
| // for type/filter name/document service/ etcpp. |
| impl_checkResultsAndAddBestFilter(stlDescriptor, sType); // Attention: sType is used as IN/OUT param here and will might be changed inside this method !!! |
| impl_validateAndSetTypeOnDescriptor(stlDescriptor, sType); |
| |
| stlDescriptor >> lDescriptor; |
| return sType; |
| } |
| |
| /*----------------------------------------------- |
| 03.07.2003 10:36 |
| -----------------------------------------------*/ |
| void TypeDetection::impl_checkResultsAndAddBestFilter(::comphelper::MediaDescriptor& rDescriptor, |
| ::rtl::OUString& sType ) |
| { |
| // a) |
| // Dont overwrite a might preselected filter! |
| ::rtl::OUString sFilter = rDescriptor.getUnpackedValueOrDefault( |
| ::comphelper::MediaDescriptor::PROP_FILTERNAME(), |
| ::rtl::OUString()); |
| if (sFilter.getLength()) |
| return; |
| |
| // b) |
| // check a preselected document service too. |
| // Then we have to search a suitable filter witin this module. |
| ::rtl::OUString sDocumentService = rDescriptor.getUnpackedValueOrDefault( |
| ::comphelper::MediaDescriptor::PROP_DOCUMENTSERVICE(), |
| ::rtl::OUString()); |
| if (sDocumentService.getLength()) |
| { |
| try |
| { |
| ::rtl::OUString sRealType = sType; |
| |
| #ifdef WORKAROUND_CSV_TXT_BUG_i60158 |
| // Workaround for #i60158# |
| // We do not have right filter for Text_Ascii in calc nor a suitable filter for CSV in writer. |
| // So we must overrule our detection and make the right things. Normaly we should have |
| // one type TextAscii and two filters registered for these one type. |
| // But then we loose automatic opening of CSV files in calc instead of opening these files |
| // inside writer. |
| if ( |
| (sDocumentService.equalsAscii("com.sun.star.sheet.SpreadsheetDocument")) && |
| ( |
| (sRealType.equalsAscii("writer_Text" )) || |
| (sRealType.equalsAscii("writer_Text_encoded")) |
| ) |
| ) |
| { |
| sRealType = ::rtl::OUString::createFromAscii("calc_Text_txt_csv_StarCalc"); |
| } |
| else |
| if ( |
| (sDocumentService.equalsAscii("com.sun.star.text.TextDocument")) && |
| (sRealType.equalsAscii("calc_Text_txt_csv_StarCalc" )) |
| ) |
| { |
| sRealType = ::rtl::OUString::createFromAscii("writer_Text"); |
| } |
| #endif // WORKAROUND_CSV_TXT_BUG_i60158 |
| |
| // SAFE -> |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| |
| // Attention: For executing next lines of code, We must be shure that |
| // all filters already loaded :-( |
| // That can disturb our "load on demand feature". But we have no other chance! |
| m_rCache->load(FilterCache::E_CONTAINS_FILTERS); |
| |
| CacheItem lIProps; |
| lIProps[PROPNAME_DOCUMENTSERVICE] <<= sDocumentService; |
| lIProps[PROPNAME_TYPE ] <<= sRealType; |
| OUStringList lFilters = m_rCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps); |
| |
| aLock.clear(); |
| // <- SAFE |
| |
| for ( OUStringList::const_iterator pIt = lFilters.begin(); |
| pIt != lFilters.end() && sFilter.getLength() == 0 ; |
| ++pIt ) |
| { |
| // SAFE -> |
| aLock.reset(); |
| try |
| { |
| CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, *pIt); |
| sal_Int32 nFlags = 0; |
| aFilter[PROPNAME_FLAGS] >>= nFlags; |
| |
| if ((nFlags & FLAGVAL_IMPORT) == FLAGVAL_IMPORT) |
| sFilter = *pIt; |
| } |
| catch(const css::uno::Exception&) {} |
| aLock.clear(); |
| // <- SAFE |
| } |
| |
| if (sFilter.getLength() > 0) |
| { |
| rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME() ] <<= sRealType; |
| rDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter; |
| sType = sRealType; |
| return; |
| } |
| } |
| catch(const css::uno::Exception&) |
| {} |
| } |
| |
| // c) |
| // We can use the preferred filter for the specified type. |
| // Such preferred filter points: |
| // - to the default filter of the preferred application |
| // - or to any other filter if no preferred filter was set. |
| // Note: It's an optimization only! |
| // It's not guaranteed, that such preferred filter exists. |
| sFilter = ::rtl::OUString(); |
| try |
| { |
| // SAFE -> |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| |
| CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sType); |
| aType[PROPNAME_PREFERREDFILTER] >>= sFilter; |
| CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter); |
| |
| aLock.clear(); |
| // <- SAFE |
| |
| // no exception => found valid type and filter => set it on the given descriptor |
| rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME() ] <<= sType ; |
| rDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter; |
| return; |
| } |
| catch(const css::uno::Exception&) |
| {} |
| |
| // d) |
| // Search for any import(!) filter, which is registered for this type. |
| sFilter = ::rtl::OUString(); |
| try |
| { |
| // SAFE -> |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| |
| // Attention: For executing next lines of code, We must be shure that |
| // all filters already loaded :-( |
| // That can disturb our "load on demand feature". But we have no other chance! |
| m_rCache->load(FilterCache::E_CONTAINS_FILTERS); |
| |
| CacheItem lIProps; |
| lIProps[PROPNAME_TYPE] <<= sType; |
| OUStringList lFilters = m_rCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps); |
| |
| aLock.clear(); |
| // <- SAFE |
| |
| OUStringList::const_iterator pIt; |
| for ( pIt = lFilters.begin(); |
| pIt != lFilters.end() ; |
| ++pIt ) |
| { |
| sFilter = *pIt; |
| |
| // SAFE -> |
| aLock.reset(); |
| try |
| { |
| CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter); |
| sal_Int32 nFlags = 0; |
| aFilter[PROPNAME_FLAGS] >>= nFlags; |
| |
| if ((nFlags & FLAGVAL_IMPORT) == FLAGVAL_IMPORT) |
| break; |
| } |
| catch(const css::uno::Exception&) |
| { continue; } |
| aLock.clear(); |
| // <- SAFE |
| |
| sFilter = ::rtl::OUString(); |
| } |
| |
| if (sFilter.getLength()) |
| { |
| rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME() ] <<= sType ; |
| rDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter; |
| return; |
| } |
| } |
| catch(const css::uno::Exception&) |
| {} |
| } |
| |
| /*----------------------------------------------- |
| 14.11.2003 12:06 |
| -----------------------------------------------*/ |
| sal_Bool TypeDetection::impl_getPreselectionForType(const ::rtl::OUString& sPreSelType, |
| const css::util::URL& aParsedURL , |
| FlatDetection& rFlatTypes ) |
| { |
| // Can be used to supress execution of some parts of this method |
| // if its already clear that detected type is valid or not. |
| // Its neccessary to use shared code at the end, which update |
| // all return parameters constistency! |
| sal_Bool bBreakDetection = sal_False; |
| |
| // Further we must know if it matches by pattern |
| // Every flat detected type by pattern wont be detected deep! |
| sal_Bool bMatchByPattern = sal_False; |
| |
| // And we must know if a preselection must be preferred, because |
| // it matches by it's extension too. |
| sal_Bool bMatchByExtension = sal_False; |
| |
| // If we e.g. collect all filters of a factory (be a forced factory preselection) |
| // we should preferr all filters of this factory, where the type match the given URL. |
| // All other types (which sorrespond to filters of the same factory - but dont match |
| // the URL) should be "used later" for detection and sorted at the end of our return vector |
| // rFlatTypes! |
| // => bPreferredPreselection = (matchByExtension || matchByURLPattern) |
| sal_Bool bPreferredPreselection = sal_False; |
| |
| // validate type |
| ::rtl::OUString sType(sPreSelType); |
| CacheItem aType; |
| try |
| { |
| // SAFE -> -------------------------- |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| aType = m_rCache->getItem(FilterCache::E_TYPE, sType); |
| aLock.clear(); |
| // <- SAFE -------------------------- |
| } |
| catch(const css::container::NoSuchElementException&) |
| { |
| sType = ::rtl::OUString(); |
| bBreakDetection = sal_True; |
| } |
| |
| if (!bBreakDetection) |
| { |
| // We cant check a preselected type for a given stream! |
| // So we must believe, that it can work ... |
| if (aParsedURL.Complete.equalsAsciiL("private:stream", 14)) |
| bBreakDetection = sal_True; |
| } |
| |
| if (!bBreakDetection) |
| { |
| // extract extension from URL .. to check it case-insensitive ! |
| INetURLObject aParser (aParsedURL.Main); |
| ::rtl::OUString sExtension = aParser.getExtension(INetURLObject::LAST_SEGMENT , |
| sal_True , |
| INetURLObject::DECODE_WITH_CHARSET); |
| sExtension = sExtension.toAsciiLowerCase(); |
| |
| // otherwhise we must know, if it matches to the given URL realy. |
| // especialy if it matches by its extension or pattern registration. |
| OUStringList lExtensions(aType[PROPNAME_EXTENSIONS]); |
| OUStringList lURLPattern(aType[PROPNAME_URLPATTERN]); |
| |
| for (OUStringList::const_iterator pIt = lExtensions.begin(); |
| pIt != lExtensions.end() ; |
| ++pIt ) |
| { |
| ::rtl::OUString sCheckExtension(pIt->toAsciiLowerCase()); |
| if (sCheckExtension.equals(sExtension)) |
| { |
| bBreakDetection = sal_True; |
| bMatchByExtension = sal_True; |
| bPreferredPreselection = sal_True; |
| break; |
| } |
| } |
| |
| if (!bBreakDetection) |
| { |
| for (OUStringList::const_iterator pIt = lURLPattern.begin(); |
| pIt != lURLPattern.end() ; |
| ++pIt ) |
| { |
| WildCard aCheck(*pIt); |
| if (aCheck.Matches(aParsedURL.Main)) |
| { |
| bBreakDetection = sal_True; |
| bMatchByPattern = sal_True; |
| bPreferredPreselection = sal_True; |
| break; |
| } |
| } |
| } |
| |
| /* |
| Comment ... why the following line of code should be comened out .-) |
| |
| This type does not seem to fit the requirements |
| But its an existing and well known type. |
| At least - [because may be the extension was missing :-( ] |
| we should try to detect this type deep ... |
| So we accept it here :-) |
| |
| if (!bBreakDetection) |
| sType = ::rtl::OUString(); |
| */ |
| } |
| |
| // if its a valid type - set it on all return values! |
| if (sType.getLength()) |
| { |
| FlatDetectionInfo aInfo; |
| aInfo.sType = sType; |
| aInfo.bMatchByExtension = bMatchByExtension; |
| aInfo.bMatchByPattern = bMatchByPattern; |
| aInfo.bPreselectedAsType = sal_True; |
| |
| if (bPreferredPreselection) |
| rFlatTypes.push_front(aInfo); |
| else |
| rFlatTypes.push_back(aInfo); |
| |
| return sal_True; |
| } |
| |
| // not valid! |
| return sal_False; |
| } |
| |
| /*----------------------------------------------- |
| 14.11.2003 12:09 |
| -----------------------------------------------*/ |
| sal_Bool TypeDetection::impl_getPreselectionForFilter(const ::rtl::OUString& sPreSelFilter, |
| const css::util::URL& aParsedURL , |
| FlatDetection& rFlatTypes ) |
| { |
| // Can be used to supress execution of some parts of this method |
| // if its already clear that detected filter is valid or not. |
| // Its neccessary to use shared code at the end, which update |
| // all return parameters constistency! |
| sal_Bool bBreakDetection = sal_False; |
| |
| // validate filter |
| ::rtl::OUString sFilter(sPreSelFilter); |
| CacheItem aFilter; |
| try |
| { |
| // SAFE -> -------------------------- |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter); |
| aLock.clear(); |
| // <- SAFE -------------------------- |
| } |
| catch(const css::container::NoSuchElementException&) |
| { |
| sFilter = ::rtl::OUString(); |
| bBreakDetection = sal_True; |
| } |
| |
| if (!bBreakDetection) |
| { |
| // get its type and check if it matches the given URL |
| ::rtl::OUString sType; |
| aFilter[PROPNAME_TYPE] >>= sType; |
| |
| bBreakDetection = impl_getPreselectionForType(sType, aParsedURL, rFlatTypes); |
| |
| // not a valid type? -> not a valid filter! |
| if (!bBreakDetection) |
| sFilter = ::rtl::OUString(); |
| } |
| |
| // We have to mark all retrieved preselection items as "preselected by filter"! |
| FlatDetection::iterator pIt; |
| for ( pIt = rFlatTypes.begin(); |
| pIt != rFlatTypes.end() ; |
| ++pIt ) |
| { |
| FlatDetectionInfo& rInfo = *pIt; |
| rInfo.bPreselectedAsType = sal_False; |
| rInfo.bPreselectedByFilter = sal_True; |
| } |
| |
| if (sFilter.getLength()) |
| return sal_True; |
| else |
| return sal_False; |
| } |
| |
| /*----------------------------------------------- |
| 14.11.2003 12:11 |
| -----------------------------------------------*/ |
| sal_Bool TypeDetection::impl_getPreselectionForDocumentService(const ::rtl::OUString& sPreSelDocumentService, |
| const css::util::URL& aParsedURL , |
| FlatDetection& rFlatTypes ) |
| { |
| // get all filters, which match to this doc service |
| OUStringList lFilters; |
| try |
| { |
| // SAFE -> -------------------------- |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| |
| // Attention: For executing next lines of code, We must be shure that |
| // all filters already loaded :-( |
| // That can disturb our "load on demand feature". But we have no other chance! |
| m_rCache->load(FilterCache::E_CONTAINS_FILTERS); |
| |
| CacheItem lIProps; |
| lIProps[PROPNAME_DOCUMENTSERVICE] <<= sPreSelDocumentService; |
| lFilters = m_rCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps); |
| |
| aLock.clear(); |
| // <- SAFE -------------------------- |
| } |
| catch(const css::container::NoSuchElementException&) |
| { |
| lFilters.clear(); |
| } |
| |
| // step over all filters, and check if its registered type |
| // match the given URL. |
| // But use temp. list of "preselected types" instead of incoming rFlatTypes list! |
| // The reason behind: we must filter the getted results. And copying of stl entries |
| // is an easier job then removing it .-) |
| FlatDetection lPreselections; |
| for (OUStringList::const_iterator pFilter = lFilters.begin(); |
| pFilter != lFilters.end() ; |
| ++pFilter ) |
| { |
| const ::rtl::OUString sFilter = *pFilter; |
| impl_getPreselectionForFilter(sFilter, aParsedURL, lPreselections); |
| } |
| |
| // We have to mark all retrieved preselection items as "preselected by document service". |
| // Further we must ignore all preselected items, which does not match the URL! |
| FlatDetection::iterator pIt; |
| for ( pIt = lPreselections.begin(); |
| pIt != lPreselections.end() ; |
| ++pIt ) |
| { |
| FlatDetectionInfo& rInfo = *pIt; |
| |
| /* |
| #i60158# |
| Preselection by DocumentService ... |
| How many filters (and corresponding types) must be checked ? |
| All or only the list of filters/types, which match to the given URL too ? |
| There is no final decision about this currently. So we make it "configurable" .-) |
| */ |
| #ifdef IGNORE_NON_URLMATCHING_TYPES_FOR_PRESELECTION_DOCUMENTSERVICE |
| if ( |
| (!rInfo.bMatchByExtension) && |
| (!rInfo.bMatchByPattern ) |
| ) |
| continue; |
| #endif |
| |
| rInfo.bPreselectedAsType = sal_False; |
| rInfo.bPreselectedByFilter = sal_False; |
| rInfo.bPreselectedByDocumentService = sal_True ; |
| rFlatTypes.push_back(rInfo); |
| } |
| |
| return sal_True; |
| } |
| |
| /*----------------------------------------------- |
| 14.11.2003 12:21 |
| -----------------------------------------------*/ |
| void TypeDetection::impl_getPreselection(const css::util::URL& aParsedURL , |
| ::comphelper::MediaDescriptor& rDescriptor, |
| FlatDetection& rFlatTypes ) |
| { |
| // done to be shure, that only valid results leave this function! |
| rFlatTypes.clear(); |
| |
| /* #i55122# |
| Sometimes we must detect files without or with real unknown extensions. |
| If it does not work /which can happen of course .-)/, the user tried to preselect |
| the right format. But some special dialogs (e.g. "Insert->Sheet From File") |
| add it's own preselection too. |
| So we have a combination of preselected values ... |
| |
| The we should preferr the most important one - set by the user. |
| And the user normaly preselects a filter or type. The preslected |
| document service cames from the dialog. |
| |
| Further it doesnt matter if the user preselected a filter or a document service. |
| A filter selection is always more explicit then a document service selection. |
| So it must be pereferred. An order between type and filter selection cant be discussed .-) |
| */ |
| |
| ::rtl::OUString sSelectedType = rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_TYPENAME(), ::rtl::OUString()); |
| if (sSelectedType.getLength()) |
| impl_getPreselectionForType(sSelectedType, aParsedURL, rFlatTypes); |
| |
| ::rtl::OUString sSelectedFilter = rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_FILTERNAME(), ::rtl::OUString()); |
| if (sSelectedFilter.getLength()) |
| impl_getPreselectionForFilter(sSelectedFilter, aParsedURL, rFlatTypes); |
| |
| ::rtl::OUString sSelectedDoc = rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_DOCUMENTSERVICE(), ::rtl::OUString()); |
| if (sSelectedDoc.getLength()) |
| impl_getPreselectionForDocumentService(sSelectedDoc, aParsedURL, rFlatTypes); |
| } |
| |
| /*----------------------------------------------- |
| 03.11.2003 09:17 |
| -----------------------------------------------*/ |
| ::rtl::OUString TypeDetection::impl_detectTypeFlatAndDeep( ::comphelper::MediaDescriptor& rDescriptor , |
| const FlatDetection& lFlatTypes , |
| sal_Bool bAllowDeep , |
| OUStringList& rUsedDetectors, |
| ::rtl::OUString& rLastChance ) |
| { |
| // reset it everytimes, so the outside code can distinguish between |
| // a set and a not set value. |
| rLastChance = ::rtl::OUString(); |
| rUsedDetectors.clear(); |
| |
| // step over all possible types for this URL. |
| // solutions: |
| // a) no types => no detection |
| // b) deep detection not allowed => return first valid type of list (because its the preferred or the first valid one) |
| // or(!) match by URLPattern => in such case a deep detection will be supressed! |
| // c) type has no detect service => safe the first occured type without a detect service |
| // as "last chance"(!). It will be used outside of this method |
| // if no further type could be detected. |
| // It must be the first one, because it can be a preferred type. |
| // Our types list was sorted by such criteria! |
| // d) detect service return a valid result => return its decision |
| // e) detect service return an invalid result |
| // or any needed information could not be |
| // getted from the cache => ignore it, and continue with search |
| |
| for (FlatDetection::const_iterator pFlatIt = lFlatTypes.begin(); |
| pFlatIt != lFlatTypes.end() ; |
| ++pFlatIt ) |
| { |
| const FlatDetectionInfo& aFlatTypeInfo = *pFlatIt; |
| ::rtl::OUString sFlatType = aFlatTypeInfo.sType; |
| |
| if (!impl_validateAndSetTypeOnDescriptor(rDescriptor, sFlatType)) |
| continue; |
| |
| // b) |
| if ( |
| (!bAllowDeep ) || |
| (aFlatTypeInfo.bMatchByPattern) |
| ) |
| { |
| return sFlatType; |
| } |
| |
| try |
| { |
| // SAFE -> ---------------------------------- |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sFlatType); |
| aLock.clear(); |
| |
| ::rtl::OUString sDetectService; |
| aType[PROPNAME_DETECTSERVICE] >>= sDetectService; |
| |
| // c) |
| if (!sDetectService.getLength()) |
| { |
| // accept or not accept flat types without deep detection: that's the question :-) |
| // May be there exists some states, where we have to use our LastChance feature instead |
| // of using the flat type directly. |
| // Here the list of task ID's, which wasrelated to these lines of code: |
| // #i47159#, #i43404#, #i46494# |
| |
| // a flat detected type without the chance for a deep detection ... but preselected by the user |
| // explicitly (means preselected as type or filter ... not as documentservice!) |
| // should be accepted. So the user can overrule our detection. |
| if ( |
| (aFlatTypeInfo.bPreselectedAsType ) || |
| (aFlatTypeInfo.bPreselectedByFilter) |
| ) |
| return sFlatType; |
| |
| // flat detected types without any registered deep detection service and not |
| // preselected by the user can be used as LAST CHANCE in case no other type could |
| // be detected. Of course only the first type without deep detector can be used. |
| // Further ones has to be ignored. |
| if (rLastChance.getLength() < 1) |
| rLastChance = sFlatType; |
| |
| continue; |
| } |
| |
| // dont forget to add every real asked deep detection service here. |
| // Such detectors will be ignored if may be "impl_detectTypeDeepOnly()" |
| // must be called later! |
| rUsedDetectors.push_back(sDetectService); |
| ::rtl::OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor); |
| |
| // d) |
| if (sDeepType.getLength()) |
| return sDeepType; |
| } |
| catch(const css::container::NoSuchElementException&) |
| {} |
| // e) |
| } |
| |
| return ::rtl::OUString(); |
| // <- SAFE ---------------------------------- |
| } |
| |
| /*----------------------------------------------- |
| 03.11.2003 09:19 |
| -----------------------------------------------*/ |
| ::rtl::OUString TypeDetection::impl_detectTypeDeepOnly( ::comphelper::MediaDescriptor& rDescriptor , |
| const OUStringList& lOutsideUsedDetectors) |
| { |
| // We must know if a detect service was already used: |
| // i) in a combined flat/deep detection scenario outside or |
| // ii) in this method for a deep detection only. |
| // Reason: Such deep detection services work differently in these two modes! |
| OUStringList lInsideUsedDetectors; |
| OUStringList::const_iterator pIt; |
| |
| // a) |
| // The list of "already used detect services" correspond to the list |
| // of preselected or flat detected types. But these detect services was called |
| // to check these types explicitly and return black/white ... yes/no only. |
| // Now they are called to return any possible result. But we should preferr |
| // these already used detect services against all other ones! |
| for ( pIt = lOutsideUsedDetectors.begin(); |
| pIt != lOutsideUsedDetectors.end() ; |
| ++pIt ) |
| { |
| const ::rtl::OUString& sDetectService = *pIt; |
| ::rtl::OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor); |
| if (sDeepType.getLength()) |
| return sDeepType; |
| lInsideUsedDetectors.push_back(sDetectService); |
| } |
| |
| // SAFE -> ---------------------------------- |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| OUStringList lDetectors = m_rCache->getItemNames(FilterCache::E_DETECTSERVICE); |
| aLock.clear(); |
| // <- SAFE ---------------------------------- |
| |
| // b) |
| // Sometimes it would be nice to ask a special set of detect services before |
| // any other detect service is asked. E.g. by using a preselection of a DocumentService. |
| // That's needed to prevent us from asking the "wrong application module" and |
| // opening the files into the "wrong application". |
| ::rtl::OUString sPreselDocumentService = rDescriptor.getUnpackedValueOrDefault( |
| ::comphelper::MediaDescriptor::PROP_DOCUMENTSERVICE(), |
| ::rtl::OUString()); |
| if (sPreselDocumentService.getLength()) |
| { |
| for ( pIt = lDetectors.begin(); |
| pIt != lDetectors.end() ; |
| ++pIt ) |
| { |
| const ::rtl::OUString& sDetectService = *pIt; |
| |
| OUStringList::const_iterator pAlreadyUsed = ::std::find(lInsideUsedDetectors.begin(), lInsideUsedDetectors.end(), sDetectService); |
| if (pAlreadyUsed != lInsideUsedDetectors.end()) |
| continue; |
| |
| // SAFE -> -------------------------------------------------------- |
| aLock.reset(); |
| |
| CacheItem lIProps; |
| lIProps[PROPNAME_DETECTSERVICE] <<= sDetectService; |
| OUStringList lTypes = m_rCache->getMatchingItemsByProps(FilterCache::E_TYPE, lIProps); |
| |
| aLock.clear(); |
| // <- SAFE -------------------------------------------------------- |
| |
| sal_Bool bMatchDetectorToDocumentService = sal_False; |
| OUStringList::const_iterator pIt2; |
| for ( pIt2 = lTypes.begin(); |
| pIt2 != lTypes.end() ; |
| ++pIt2 ) |
| { |
| const ::rtl::OUString& sType = *pIt2; |
| |
| try |
| { |
| // SAFE -> ---------------------------------------------------- |
| aLock.reset(); |
| |
| CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sType); |
| ::rtl::OUString sFilter; |
| aType[PROPNAME_PREFERREDFILTER] >>= sFilter; |
| CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter); |
| ::rtl::OUString sCheckDocumentService; |
| aFilter[PROPNAME_DOCUMENTSERVICE] >>= sCheckDocumentService; |
| |
| aLock.clear(); |
| // <- SAFE |
| |
| if (sCheckDocumentService.equals(sPreselDocumentService)) |
| { |
| bMatchDetectorToDocumentService = sal_True; |
| break; |
| } |
| } |
| catch(const css::uno::Exception&) |
| { continue; } |
| } |
| |
| if (bMatchDetectorToDocumentService) |
| { |
| ::rtl::OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor); |
| if (sDeepType.getLength()) |
| return sDeepType; |
| lInsideUsedDetectors.push_back(sDetectService); |
| } |
| } |
| } |
| |
| // c) |
| // Last chance. No "used detectors", no "preselected detectors" ... ask any existing detect services |
| // for this till know unknown format. |
| for ( pIt = lDetectors.begin(); |
| pIt != lDetectors.end() ; |
| ++pIt ) |
| { |
| const ::rtl::OUString& sDetectService = *pIt; |
| |
| OUStringList::const_iterator pAlreadyUsed = ::std::find(lInsideUsedDetectors.begin(), lInsideUsedDetectors.end(), sDetectService); |
| if (pAlreadyUsed != lInsideUsedDetectors.end()) |
| continue; |
| |
| ::rtl::OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor); |
| if (sDeepType.getLength()) |
| return sDeepType; |
| } |
| |
| return ::rtl::OUString(); |
| } |
| |
| /*----------------------------------------------- |
| 07.03.2005 11:13 |
| -----------------------------------------------*/ |
| void TypeDetection::impl_seekStreamToZero(comphelper::MediaDescriptor& rDescriptor) |
| { |
| // try to seek to 0 ... |
| // But because XSeekable is an optional interface ... try it only .-) |
| css::uno::Reference< css::io::XInputStream > xStream = rDescriptor.getUnpackedValueOrDefault( |
| ::comphelper::MediaDescriptor::PROP_INPUTSTREAM(), |
| css::uno::Reference< css::io::XInputStream >()); |
| css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY); |
| if (xSeek.is()) |
| { |
| try |
| { |
| xSeek->seek(0); |
| } |
| catch(const css::uno::RuntimeException& exRun) |
| { throw exRun; } |
| catch(const css::uno::Exception&) |
| {} |
| } |
| } |
| |
| /*----------------------------------------------- |
| 30.10.2003 15:12 |
| -----------------------------------------------*/ |
| ::rtl::OUString TypeDetection::impl_askDetectService(const ::rtl::OUString& sDetectService, |
| ::comphelper::MediaDescriptor& rDescriptor ) |
| { |
| // Open the stream and add it to the media descriptor if this method is called for the first time. |
| // All following requests to this method will detect, that there already exists a stream .-) |
| // Attention: This method throws an exception if the stream could not be opened. |
| // It's important to break any further detection in such case. |
| // Catch it on the highest detection level only !!! |
| impl_openStream(rDescriptor); |
| |
| // seek to 0 is an optional feature to be more robust against |
| // "simple implemented detect services" .-) |
| impl_seekStreamToZero(rDescriptor); |
| |
| css::uno::Reference< css::document::XExtendedFilterDetection > xDetector; |
| css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR; |
| |
| // SAFE -> |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| xSMGR = m_xSMGR; |
| aLock.clear(); |
| // <- SAFE |
| |
| // Attention! If e.g. an office module was not installed sometimes we find a |
| // registered detect service, which is referred inside the configuration ... but not realy |
| // installed. On the other side we use third party components here, which can make trouble anyway. |
| // So we should handle errors during creation of such services more gracefully .-) |
| xDetector = css::uno::Reference< css::document::XExtendedFilterDetection >( |
| xSMGR->createInstance(sDetectService), |
| css::uno::UNO_QUERY); |
| |
| if ( ! xDetector.is()) |
| return ::rtl::OUString(); |
| |
| ::rtl::OUString sDeepType; |
| try |
| { |
| // start deep detection |
| // Dont forget to convert stl descriptor to its uno representation. |
| |
| /* Attention! |
| You have to use an explicit instance of this uno sequence ... |
| Because its used as an in out parameter. And in case of a temp. used object |
| we will run into memory corruptions! |
| */ |
| css::uno::Sequence< css::beans::PropertyValue > lDescriptor; |
| rDescriptor >> lDescriptor; |
| sDeepType = xDetector->detect(lDescriptor); |
| rDescriptor << lDescriptor; |
| } |
| catch(const css::uno::Exception&) |
| { |
| // We should ignore errors here. |
| // Thrown exceptions mostly will end in crash recovery ... |
| // But might be we find another deep detection service which can detect the same |
| // document without a problem .-) |
| sDeepType = ::rtl::OUString(); |
| } |
| |
| // seek to 0 is an optional feature to be more robust against |
| // "simple implemented detect services" .-) |
| impl_seekStreamToZero(rDescriptor); |
| |
| // analyze the results |
| // a) detect service returns "" => return "" too and remove TYPE/FILTER prop from descriptor |
| // b) returned type is unknown => return "" too and remove TYPE/FILTER prop from descriptor |
| // c) returned type is valid => check TYPE/FILTER props inside descriptor and return the type |
| |
| // this special helper checks for a valid type |
| // and set right values on the descriptor! |
| sal_Bool bValidType = impl_validateAndSetTypeOnDescriptor(rDescriptor, sDeepType); |
| if (bValidType) |
| return sDeepType; |
| |
| return ::rtl::OUString(); |
| } |
| |
| /*----------------------------------------------- |
| 17.12.2004 13:47 |
| -----------------------------------------------*/ |
| ::rtl::OUString TypeDetection::impl_askUserForTypeAndFilterIfAllowed(::comphelper::MediaDescriptor& rDescriptor) |
| { |
| // SAFE -> |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; |
| aLock.clear(); |
| // <- SAFE |
| |
| css::uno::Reference< css::task::XInteractionHandler > xInteraction = |
| rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_INTERACTIONHANDLER(), |
| css::uno::Reference< css::task::XInteractionHandler >()); |
| |
| if (!xInteraction.is()) |
| return ::rtl::OUString(); |
| |
| ::rtl::OUString sURL = |
| rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_URL(), |
| ::rtl::OUString()); |
| |
| css::uno::Reference< css::io::XInputStream > xStream = |
| rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_INPUTSTREAM(), |
| css::uno::Reference< css::io::XInputStream >()); |
| |
| // Dont distrub the user for "non existing files - means empty URLs" or |
| // if we was forced to detect a stream. |
| // Reason behind: We must be shure to ask user for "unknown contents" only ... |
| // and not for "missing files". Especialy if detection is done by a stream only |
| // we cant check if the stream points to an "existing content"! |
| if ( |
| (!sURL.getLength() ) || // "non existing file" ? |
| (!xStream.is() ) || // non existing file ! |
| (sURL.equalsIgnoreAsciiCaseAsciiL("private:stream", 14)) // not a good idea .-) |
| ) |
| return ::rtl::OUString(); |
| |
| try |
| { |
| // create a new request to ask user for it's decision about the usable filter |
| ::framework::RequestFilterSelect aRequest(sURL); |
| xInteraction->handle(aRequest.GetRequest()); |
| |
| // "Cancel" pressed? => return with error |
| if (aRequest.isAbort()) |
| return ::rtl::OUString(); |
| |
| // "OK" pressed => verify the selected filter, get it's coressponding |
| // type and return it. (BTW: We must update the media descriptor here ...) |
| // The user selected explicitly a filter ... but normaly we are interested on |
| // a type here only. But we must be shure, that the selected filter is used |
| // too and no ambigous filter registration disturb us .-) |
| |
| ::rtl::OUString sFilter = aRequest.getFilter(); |
| if (!impl_validateAndSetFilterOnDescriptor(rDescriptor, sFilter)) |
| return ::rtl::OUString(); |
| |
| ::rtl::OUString sType; |
| rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME()] >>= sType; |
| return sType; |
| } |
| catch(const css::uno::Exception&) |
| {} |
| |
| return ::rtl::OUString(); |
| } |
| |
| /*----------------------------------------------- |
| 10.03.2004 10:30 |
| -----------------------------------------------*/ |
| void TypeDetection::impl_openStream(::comphelper::MediaDescriptor& rDescriptor) |
| throw (css::uno::Exception) |
| { |
| sal_Bool bSuccess = sal_False; |
| ::rtl::OUString sURL = rDescriptor.getUnpackedValueOrDefault( ::comphelper::MediaDescriptor::PROP_URL(), ::rtl::OUString() ); |
| sal_Bool bRequestedReadOnly = rDescriptor.getUnpackedValueOrDefault( ::comphelper::MediaDescriptor::PROP_READONLY(), sal_False ); |
| if ( sURL.getLength() && ::utl::LocalFileHelper::IsLocalFile( INetURLObject( sURL ).GetMainURL( INetURLObject::NO_DECODE ) ) ) |
| { |
| // OOo uses own file locking mechanics in case of local file |
| bSuccess = rDescriptor.addInputStreamOwnLock(); |
| } |
| else |
| bSuccess = rDescriptor.addInputStream(); |
| |
| if ( !bSuccess ) |
| throw css::uno::Exception(_FILTER_CONFIG_FROM_ASCII_("Could not open stream."), static_cast< css::document::XTypeDetection* >(this)); |
| |
| if ( !bRequestedReadOnly ) |
| { |
| // The MediaDescriptor implementation adds ReadOnly argument if the file can not be opened for writing |
| // this argument should be either removed or an additional argument should be added so that application |
| // can separate the case when the user explicitly requests readonly document. |
| // The current solution is to remove it here. |
| rDescriptor.erase( ::comphelper::MediaDescriptor::PROP_READONLY() ); |
| } |
| } |
| |
| /*----------------------------------------------- |
| 04.07.2003 13:47 |
| -----------------------------------------------*/ |
| void TypeDetection::impl_removeTypeFilterFromDescriptor(::comphelper::MediaDescriptor& rDescriptor) |
| { |
| ::comphelper::MediaDescriptor::iterator pItType = rDescriptor.find(::comphelper::MediaDescriptor::PROP_TYPENAME() ); |
| ::comphelper::MediaDescriptor::iterator pItFilter = rDescriptor.find(::comphelper::MediaDescriptor::PROP_FILTERNAME()); |
| if (pItType != rDescriptor.end()) |
| rDescriptor.erase(pItType); |
| if (pItFilter != rDescriptor.end()) |
| rDescriptor.erase(pItFilter); |
| } |
| |
| /*----------------------------------------------- |
| 14.10.2003 11:15 |
| -----------------------------------------------*/ |
| sal_Bool TypeDetection::impl_validateAndSetTypeOnDescriptor( ::comphelper::MediaDescriptor& rDescriptor, |
| const ::rtl::OUString& sType ) |
| { |
| // SAFE -> |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| if (m_rCache->hasItem(FilterCache::E_TYPE, sType)) |
| { |
| rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME()] <<= sType; |
| return sal_True; |
| } |
| aLock.clear(); |
| // <- SAFE |
| |
| // remove all related informations from the descriptor |
| impl_removeTypeFilterFromDescriptor(rDescriptor); |
| return sal_False; |
| } |
| |
| /*----------------------------------------------- |
| 04.07.2003 14:01 |
| -----------------------------------------------*/ |
| sal_Bool TypeDetection::impl_validateAndSetFilterOnDescriptor( ::comphelper::MediaDescriptor& rDescriptor, |
| const ::rtl::OUString& sFilter ) |
| { |
| try |
| { |
| // SAFE -> |
| ::osl::ResettableMutexGuard aLock(m_aLock); |
| |
| CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter); |
| ::rtl::OUString sType; |
| aFilter[PROPNAME_TYPE] >>= sType; |
| CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sType); |
| |
| aLock.clear(); |
| // <- SAFE |
| |
| // found valid type and filter => set it on the given descriptor |
| rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME() ] <<= sType ; |
| rDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter; |
| return sal_True; |
| } |
| catch(const css::container::NoSuchElementException&){} |
| |
| // remove all related informations from the descriptor |
| impl_removeTypeFilterFromDescriptor(rDescriptor); |
| return sal_False; |
| } |
| |
| /*----------------------------------------------- |
| 03.07.2003 10:36 |
| -----------------------------------------------*/ |
| ::rtl::OUString TypeDetection::impl_getImplementationName() |
| { |
| return ::rtl::OUString::createFromAscii("com.sun.star.comp.filter.config.TypeDetection"); |
| } |
| |
| /*----------------------------------------------- |
| 03.07.2003 11:27 |
| -----------------------------------------------*/ |
| css::uno::Sequence< ::rtl::OUString > TypeDetection::impl_getSupportedServiceNames() |
| { |
| css::uno::Sequence< ::rtl::OUString > lServiceNames(1); |
| lServiceNames[0] = ::rtl::OUString::createFromAscii("com.sun.star.document.TypeDetection"); |
| return lServiceNames; |
| } |
| |
| /*----------------------------------------------- |
| 09.07.2003 08:02 |
| -----------------------------------------------*/ |
| css::uno::Reference< css::uno::XInterface > SAL_CALL TypeDetection::impl_createInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR) |
| { |
| TypeDetection* pNew = new TypeDetection(xSMGR); |
| return css::uno::Reference< css::uno::XInterface >(static_cast< css::document::XTypeDetection* >(pNew), css::uno::UNO_QUERY); |
| } |
| |
| } // namespace config |
| } // namespace filter |