/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fltlst.hxx" #include #include #include #if defined(DBG_UTIL) unsigned SfxStack::nLevel = 0; #endif using namespace com::sun::star; static SfxFilterList_Impl* pFilterArr = nullptr; static bool bFirstRead = true; static void CreateFilterArr() { static SfxFilterList_Impl theSfxFilterArray; pFilterArr = &theSfxFilterArray; static SfxFilterListener theSfxFilterListener; } static OUString ToUpper_Impl( const OUString &rStr ) { return SvtSysLocale().GetCharClass().uppercase( rStr ); } class SfxFilterContainer_Impl { public: OUString aName; explicit SfxFilterContainer_Impl( const OUString& rName ) : aName( rName ) { } }; std::shared_ptr SfxFilterContainer::GetFilter4EA(const OUString& rEA, SfxFilterFlags nMust, SfxFilterFlags nDont) const { SfxFilterMatcher aMatch(pImpl->aName); return aMatch.GetFilter4EA(rEA, nMust, nDont); } std::shared_ptr SfxFilterContainer::GetFilter4Extension(const OUString& rExt, SfxFilterFlags nMust, SfxFilterFlags nDont) const { SfxFilterMatcher aMatch(pImpl->aName); return aMatch.GetFilter4Extension(rExt, nMust, nDont); } std::shared_ptr SfxFilterContainer::GetFilter4FilterName(const OUString& rName, SfxFilterFlags nMust, SfxFilterFlags nDont) const { SfxFilterMatcher aMatch(pImpl->aName); return aMatch.GetFilter4FilterName(rName, nMust, nDont); } std::shared_ptr SfxFilterContainer::GetAnyFilter( SfxFilterFlags nMust, SfxFilterFlags nDont ) const { SfxFilterMatcher aMatch( pImpl->aName ); return aMatch.GetAnyFilter( nMust, nDont ); } SfxFilterContainer::SfxFilterContainer( const OUString& rName ) : pImpl( new SfxFilterContainer_Impl( rName ) ) { } SfxFilterContainer::~SfxFilterContainer() { } OUString const & SfxFilterContainer::GetName() const { return pImpl->aName; } std::shared_ptr SfxFilterContainer::GetDefaultFilter_Impl( std::u16string_view rName ) { // Try to find out the type of factory. // Interpret given name as Service- and ShortName! SvtModuleOptions aOpt; SvtModuleOptions::EFactory eFactory = SvtModuleOptions::ClassifyFactoryByServiceName(rName); if (eFactory == SvtModuleOptions::EFactory::UNKNOWN_FACTORY) eFactory = SvtModuleOptions::ClassifyFactoryByShortName(rName); // could not classify factory by its service nor by its short name. // Must be an unknown factory! => return NULL if (eFactory == SvtModuleOptions::EFactory::UNKNOWN_FACTORY) return nullptr; // For the following code we need some additional information. OUString sServiceName = aOpt.GetFactoryName(eFactory); OUString sDefaultFilter = aOpt.GetFactoryDefaultFilter(eFactory); // Try to get the default filter. Don't forget to verify it. // May the set default filter does not exists any longer or // does not fit the given factory. const SfxFilterMatcher aMatcher; std::shared_ptr pFilter = aMatcher.GetFilter4FilterName(sDefaultFilter); if ( pFilter && !pFilter->GetServiceName().equalsIgnoreAsciiCase(sServiceName) ) { pFilter = nullptr; } // If at least no default filter could be located - use any filter of this // factory. if (!pFilter) { if ( bFirstRead ) ReadFilters_Impl(); for (const std::shared_ptr& pCheckFilter : *pFilterArr) { if ( pCheckFilter->GetServiceName().equalsIgnoreAsciiCase(sServiceName) ) { pFilter = pCheckFilter; break; } } } return pFilter; } // Impl-Data is shared between all FilterMatchers of the same factory class SfxFilterMatcher_Impl { public: OUString aName; mutable SfxFilterList_Impl* pList; // is created on demand void InitForIterating() const; void Update() const; explicit SfxFilterMatcher_Impl(const OUString &rName) : aName(rName) , pList(nullptr) { } ~SfxFilterMatcher_Impl() { // SfxFilterMatcher_Impl::InitForIterating() will set pList to // either the global filter array matcher pFilterArr, or to // a new SfxFilterList_Impl. if (pList != pFilterArr) delete pList; } }; namespace { std::vector > aImplArr; int nSfxFilterMatcherCount; SfxFilterMatcher_Impl & getSfxFilterMatcher_Impl(const OUString &rName) { OUString aName; if (!rName.isEmpty()) aName = SfxObjectShell::GetServiceNameFromFactory(rName); // find the impl-Data of any comparable FilterMatcher that was created // previously for (std::unique_ptr& aImpl : aImplArr) if (aImpl->aName == aName) return *aImpl; // first Matcher created for this factory aImplArr.push_back(std::make_unique(aName)); return *aImplArr.back(); } } SfxFilterMatcher::SfxFilterMatcher( const OUString& rName ) : m_rImpl( getSfxFilterMatcher_Impl(rName) ) { ++nSfxFilterMatcherCount; } SfxFilterMatcher::SfxFilterMatcher() : m_rImpl( getSfxFilterMatcher_Impl(OUString()) ) { // global FilterMatcher always uses global filter array (also created on // demand) ++nSfxFilterMatcherCount; } SfxFilterMatcher::~SfxFilterMatcher() { --nSfxFilterMatcherCount; if (nSfxFilterMatcherCount == 0) aImplArr.clear(); } void SfxFilterMatcher_Impl::Update() const { if ( pList ) { // this List was already used pList->clear(); for (const std::shared_ptr& pFilter : *pFilterArr) { if ( pFilter->GetServiceName() == aName ) pList->push_back( pFilter ); } } } void SfxFilterMatcher_Impl::InitForIterating() const { if ( pList ) return; if ( bFirstRead ) // global filter array has not been created yet SfxFilterContainer::ReadFilters_Impl(); if ( !aName.isEmpty() ) { // matcher of factory: use only filters of that document type pList = new SfxFilterList_Impl; Update(); } else { // global matcher: use global filter array pList = pFilterArr; } } std::shared_ptr SfxFilterMatcher::GetAnyFilter( SfxFilterFlags nMust, SfxFilterFlags nDont ) const { m_rImpl.InitForIterating(); for (const std::shared_ptr& pFilter : *m_rImpl.pList) { SfxFilterFlags nFlags = pFilter->GetFilterFlags(); if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) ) return pFilter; } return nullptr; } ErrCode SfxFilterMatcher::GuessFilterIgnoringContent( SfxMedium const & rMedium, std::shared_ptr& rpFilter ) const { uno::Reference xDetection( comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY); OUString sTypeName; try { sTypeName = xDetection->queryTypeByURL( rMedium.GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); } catch (uno::Exception&) { } rpFilter = nullptr; if ( !sTypeName.isEmpty() ) { // make sure filter list is initialized m_rImpl.InitForIterating(); rpFilter = GetFilter4EA( sTypeName ); } return rpFilter ? ERRCODE_NONE : ERRCODE_ABORT; } ErrCode SfxFilterMatcher::GuessFilter( SfxMedium& rMedium, std::shared_ptr& rpFilter, SfxFilterFlags nMust, SfxFilterFlags nDont ) const { return GuessFilterControlDefaultUI( rMedium, rpFilter, nMust, nDont ); } ErrCode SfxFilterMatcher::GuessFilterControlDefaultUI( SfxMedium& rMedium, std::shared_ptr& rpFilter, SfxFilterFlags nMust, SfxFilterFlags nDont ) const { std::shared_ptr pOldFilter = rpFilter; // no detection service -> nothing to do ! uno::Reference xDetection( comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY); if (!xDetection.is()) return ERRCODE_ABORT; try { // open the stream one times only ... // Otherwise it will be tried more than once and show the same interaction more than once ... OUString sURL( rMedium.GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); uno::Reference< io::XInputStream > xInStream = rMedium.GetInputStream(); OUString aFilterName; OUString sTypeName; // stream exists => deep detection (with preselection ... if possible) if (xInStream.is()) { utl::MediaDescriptor aDescriptor; aDescriptor[utl::MediaDescriptor::PROP_URL ] <<= sURL; aDescriptor[utl::MediaDescriptor::PROP_INPUTSTREAM ] <<= xInStream; aDescriptor[utl::MediaDescriptor::PROP_INTERACTIONHANDLER] <<= rMedium.GetInteractionHandler(); SfxStringItem const * it = static_cast( rMedium.GetItemSet()->GetItem(SID_REFERER)); if (it != nullptr) { aDescriptor[utl::MediaDescriptor::PROP_REFERRER] <<= it->GetValue(); } if ( !m_rImpl.aName.isEmpty() ) aDescriptor[utl::MediaDescriptor::PROP_DOCUMENTSERVICE] <<= m_rImpl.aName; if ( pOldFilter ) { aDescriptor[utl::MediaDescriptor::PROP_TYPENAME ] <<= pOldFilter->GetTypeName(); aDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] <<= pOldFilter->GetFilterName(); } uno::Sequence< beans::PropertyValue > lDescriptor = aDescriptor.getAsConstPropertyValueList(); sTypeName = xDetection->queryTypeByDescriptor(lDescriptor, true); // lDescriptor is used as In/Out param ... don't use aDescriptor.getAsConstPropertyValueList() directly! for (const auto& rProp : std::as_const(lDescriptor)) { if (rProp.Name == "FilterName") // Type detection picked a preferred filter for this format. aFilterName = rProp.Value.get(); } } // no stream exists => try flat detection without preselection as fallback else sTypeName = xDetection->queryTypeByURL(sURL); if (!sTypeName.isEmpty()) { std::shared_ptr pNewFilter; if (!aFilterName.isEmpty()) // Type detection returned a suitable filter for this. Use it. pNewFilter = SfxFilter::GetFilterByName(aFilterName); // fdo#78742 respect requested document service if set if (!pNewFilter || (!m_rImpl.aName.isEmpty() && m_rImpl.aName != pNewFilter->GetServiceName())) { // detect filter by given type // In case of this matcher is bound to a particular document type: // If there is no acceptable type for this document at all, the type detection has possibly returned something else. // The DocumentService property is only a preselection, and all preselections are considered as optional! // This "wrong" type will be sorted out now because we match only allowed filters to the detected type uno::Sequence< beans::NamedValue > lQuery { { "Name", css::uno::Any(sTypeName) } }; pNewFilter = GetFilterForProps(lQuery, nMust, nDont); } if (pNewFilter) { rpFilter = pNewFilter; return ERRCODE_NONE; } } } catch (const uno::Exception&) {} return ERRCODE_ABORT; } bool SfxFilterMatcher::IsFilterInstalled_Impl( const std::shared_ptr& pFilter ) { if ( pFilter->GetFilterFlags() & SfxFilterFlags::MUSTINSTALL ) { // Here could a re-installation be offered OUString aText( SfxResId(STR_FILTER_NOT_INSTALLED) ); aText = aText.replaceFirst( "$(FILTER)", pFilter->GetUIName() ); std::unique_ptr xQueryBox(Application::CreateMessageDialog(nullptr, VclMessageType::Question, VclButtonsType::YesNo, aText)); xQueryBox->set_default_response(RET_YES); short nRet = xQueryBox->run(); if ( nRet == RET_YES ) { #ifdef DBG_UTIL // Start Setup std::unique_ptr xInfoBox(Application::CreateMessageDialog(nullptr, VclMessageType::Info, VclButtonsType::Ok, "Here should the Setup now be starting!")); xInfoBox->run(); #endif // Installation must still give feedback if it worked or not, // then the Filterflag be deleted } return ( !(pFilter->GetFilterFlags() & SfxFilterFlags::MUSTINSTALL) ); } else if ( pFilter->GetFilterFlags() & SfxFilterFlags::CONSULTSERVICE ) { OUString aText( SfxResId(STR_FILTER_CONSULT_SERVICE) ); aText = aText.replaceFirst( "$(FILTER)", pFilter->GetUIName() ); std::unique_ptr xInfoBox(Application::CreateMessageDialog(nullptr, VclMessageType::Info, VclButtonsType::Ok, aText)); xInfoBox->run(); return false; } else return true; } ErrCode SfxFilterMatcher::DetectFilter( SfxMedium& rMedium, std::shared_ptr& rpFilter ) const /* [Description] Here the Filter selection box is pulled up. Otherwise GuessFilter */ { std::shared_ptr pOldFilter = rMedium.GetFilter(); if ( pOldFilter ) { if( !IsFilterInstalled_Impl( pOldFilter ) ) pOldFilter = nullptr; else { const SfxStringItem* pSalvageItem = SfxItemSet::GetItem(rMedium.GetItemSet(), SID_DOC_SALVAGE, false); if ( ( pOldFilter->GetFilterFlags() & SfxFilterFlags::PACKED ) && pSalvageItem ) // Salvage is always done without packing pOldFilter = nullptr; } } std::shared_ptr pFilter = pOldFilter; bool bPreview = rMedium.IsPreview_Impl(); const SfxStringItem* pReferer = SfxItemSet::GetItem(rMedium.GetItemSet(), SID_REFERER, false); if ( bPreview && rMedium.IsRemote() && ( !pReferer || !pReferer->GetValue().match("private:searchfolder:") ) ) return ERRCODE_ABORT; ErrCode nErr = GuessFilter( rMedium, pFilter ); if ( nErr == ERRCODE_ABORT ) return nErr; if ( nErr == ERRCODE_IO_PENDING ) { rpFilter = pFilter; return nErr; } if ( !pFilter ) { std::shared_ptr pInstallFilter; // Now test the filter which are not installed (ErrCode is irrelevant) GuessFilter( rMedium, pInstallFilter, SfxFilterFlags::IMPORT, SfxFilterFlags::CONSULTSERVICE ); if ( pInstallFilter ) { if ( IsFilterInstalled_Impl( pInstallFilter ) ) // Maybe the filter was installed afterwards. pFilter = pInstallFilter; } else { // Now test the filter, which first must be obtained by Star // (ErrCode is irrelevant) GuessFilter( rMedium, pInstallFilter, SfxFilterFlags::IMPORT, SfxFilterFlags::NONE ); if ( pInstallFilter ) IsFilterInstalled_Impl( pInstallFilter ); } } bool bHidden = bPreview; const SfxStringItem* pFlags = SfxItemSet::GetItem(rMedium.GetItemSet(), SID_OPTIONS, false); if ( !bHidden && pFlags ) { OUString aFlags( pFlags->GetValue() ); aFlags = aFlags.toAsciiUpperCase(); if( -1 != aFlags.indexOf( 'H' ) ) bHidden = true; } rpFilter = pFilter; if ( bHidden ) nErr = pFilter ? ERRCODE_NONE : ERRCODE_ABORT; return nErr; } std::shared_ptr SfxFilterMatcher::GetFilterForProps( const css::uno::Sequence < beans::NamedValue >& aSeq, SfxFilterFlags nMust, SfxFilterFlags nDont ) const { uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory(); if( !xServiceManager ) return nullptr; static constexpr OUStringLiteral sTypeDetection = u"com.sun.star.document.TypeDetection"; uno::Reference< container::XContainerQuery > xTypeCFG( xServiceManager->createInstance( sTypeDetection ), uno::UNO_QUERY ); if ( !xTypeCFG ) return nullptr; // make query for all types matching the properties uno::Reference < css::container::XEnumeration > xEnum = xTypeCFG->createSubSetEnumerationByProperties( aSeq ); uno::Sequence aProps; while ( xEnum->hasMoreElements() ) { static constexpr OUStringLiteral sPreferredFilter = u"PreferredFilter"; static constexpr OUStringLiteral sName = u"Name"; xEnum->nextElement() >>= aProps; OUString aValue, aName; for( const auto & rPropVal : aProps) { if (rPropVal.Name == sPreferredFilter) rPropVal.Value >>= aValue; else if (rPropVal.Name == sName) rPropVal.Value >>= aName; } // try to get the preferred filter (works without loading all filters!) if ( !aValue.isEmpty() ) { std::shared_ptr pFilter = SfxFilter::GetFilterByName( aValue ); if ( !pFilter || (pFilter->GetFilterFlags() & nMust) != nMust || (pFilter->GetFilterFlags() & nDont ) ) // check for filter flags // pFilter == 0: if preferred filter is a Writer filter, but Writer module is not installed continue; if ( !m_rImpl.aName.isEmpty() ) { // if this is not the global FilterMatcher: check if filter matches the document type if ( pFilter->GetServiceName() != m_rImpl.aName ) { // preferred filter belongs to another document type; now we must search the filter m_rImpl.InitForIterating(); pFilter = GetFilter4EA( aName, nMust, nDont ); if ( pFilter ) return pFilter; } else return pFilter; } else return pFilter; } } return nullptr; } std::shared_ptr SfxFilterMatcher::GetFilter4Mime( const OUString& rMediaType, SfxFilterFlags nMust, SfxFilterFlags nDont ) const { if ( m_rImpl.pList ) { for (const std::shared_ptr& pFilter : *m_rImpl.pList) { SfxFilterFlags nFlags = pFilter->GetFilterFlags(); if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetMimeType() == rMediaType ) return pFilter; } return nullptr; } css::uno::Sequence < css::beans::NamedValue > aSeq { { "MediaType", css::uno::Any(rMediaType) } }; return GetFilterForProps( aSeq, nMust, nDont ); } std::shared_ptr SfxFilterMatcher::GetFilter4EA( const OUString& rType, SfxFilterFlags nMust, SfxFilterFlags nDont ) const { if ( m_rImpl.pList ) { std::shared_ptr pFirst; for (const std::shared_ptr& pFilter : *m_rImpl.pList) { SfxFilterFlags nFlags = pFilter->GetFilterFlags(); if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetTypeName() == rType ) { if (nFlags & SfxFilterFlags::PREFERED) return pFilter; if (!pFirst) pFirst = pFilter; } } if (pFirst) return pFirst; return nullptr; } css::uno::Sequence < css::beans::NamedValue > aSeq { { "Name", css::uno::Any(rType) } }; return GetFilterForProps( aSeq, nMust, nDont ); } std::shared_ptr SfxFilterMatcher::GetFilter4Extension( const OUString& rExt, SfxFilterFlags nMust, SfxFilterFlags nDont ) const { if ( m_rImpl.pList ) { if (OUString sExt = ToUpper_Impl(rExt); !sExt.isEmpty()) { if (sExt[0] != '.') sExt = "." + sExt; for (const std::shared_ptr& pFilter : *m_rImpl.pList) { SfxFilterFlags nFlags = pFilter->GetFilterFlags(); if ((nFlags & nMust) == nMust && !(nFlags & nDont)) { OUString sWildCard = ToUpper_Impl(pFilter->GetWildcard().getGlob()); WildCard aCheck(sWildCard, ';'); if (aCheck.Matches(sExt)) return pFilter; } } } return nullptr; } // Use extension without dot! OUString sExt( rExt ); if ( sExt.startsWith(".") ) sExt = sExt.copy(1); css::uno::Sequence < css::beans::NamedValue > aSeq { { "Extensions", css::uno::Any(uno::Sequence < OUString > { sExt } ) } }; return GetFilterForProps( aSeq, nMust, nDont ); } std::shared_ptr SfxFilterMatcher::GetFilter4ClipBoardId( SotClipboardFormatId nId, SfxFilterFlags nMust, SfxFilterFlags nDont ) const { if (nId == SotClipboardFormatId::NONE) return nullptr; css::uno::Sequence < css::beans::NamedValue > aSeq { { "ClipboardFormat", css::uno::Any(SotExchange::GetFormatName( nId )) } }; return GetFilterForProps( aSeq, nMust, nDont ); } std::shared_ptr SfxFilterMatcher::GetFilter4UIName( std::u16string_view rName, SfxFilterFlags nMust, SfxFilterFlags nDont ) const { m_rImpl.InitForIterating(); std::shared_ptr pFirstFilter; for (const std::shared_ptr& pFilter : *m_rImpl.pList) { SfxFilterFlags nFlags = pFilter->GetFilterFlags(); if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetUIName() == rName ) { if ( pFilter->GetFilterFlags() & SfxFilterFlags::PREFERED ) return pFilter; else if ( !pFirstFilter ) pFirstFilter = pFilter; } } return pFirstFilter; } std::shared_ptr SfxFilterMatcher::GetFilter4FilterName( const OUString& rName, SfxFilterFlags nMust, SfxFilterFlags nDont ) const { std::u16string_view aName( rName ); sal_Int32 nIndex = rName.indexOf(": "); if ( nIndex != -1 ) { SAL_WARN( "sfx.bastyp", "Old filter name used!"); aName = rName.subView( nIndex + 2 ); } if ( bFirstRead ) { uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory(); uno::Reference< container::XNameAccess > xFilterCFG ; uno::Reference< container::XNameAccess > xTypeCFG ; if( xServiceManager.is() ) { static constexpr OUStringLiteral sFilterFactory = u"com.sun.star.document.FilterFactory"; static constexpr OUStringLiteral sTypeDetection = u"com.sun.star.document.TypeDetection"; xFilterCFG.set( xServiceManager->createInstance( sFilterFactory ), uno::UNO_QUERY ); xTypeCFG.set( xServiceManager->createInstance( sTypeDetection ), uno::UNO_QUERY ); } if( xFilterCFG.is() && xTypeCFG.is() ) { if ( !pFilterArr ) CreateFilterArr(); else { for (const std::shared_ptr& pFilter : *pFilterArr) { SfxFilterFlags nFlags = pFilter->GetFilterFlags(); if ((nFlags & nMust) == nMust && !(nFlags & nDont) && pFilter->GetFilterName().equalsIgnoreAsciiCase(aName)) return pFilter; } } SfxFilterContainer::ReadSingleFilter_Impl( rName, xTypeCFG, xFilterCFG, false ); } } SfxFilterList_Impl* pList = m_rImpl.pList; if ( !pList ) pList = pFilterArr; for (const std::shared_ptr& pFilter : *pList) { SfxFilterFlags nFlags = pFilter->GetFilterFlags(); if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetFilterName().equalsIgnoreAsciiCase(aName)) return pFilter; } return nullptr; } IMPL_LINK( SfxFilterMatcher, MaybeFileHdl_Impl, OUString*, pString, bool ) { std::shared_ptr pFilter = GetFilter4Extension( *pString ); return pFilter && !pFilter->GetWildcard().Matches(u"") && !pFilter->GetWildcard().Matches(u"*.*") && !pFilter->GetWildcard().Matches(u"*"); } SfxFilterMatcherIter::SfxFilterMatcherIter( const SfxFilterMatcher& rMatcher, SfxFilterFlags nOrMaskP, SfxFilterFlags nAndMaskP ) : nOrMask( nOrMaskP ), nAndMask( nAndMaskP ), nCurrent(0), m_rMatch(rMatcher.m_rImpl) { if( nOrMask == static_cast(0xffff) ) //Due to faulty build on s nOrMask = SfxFilterFlags::NONE; m_rMatch.InitForIterating(); } std::shared_ptr SfxFilterMatcherIter::Find_Impl() { std::shared_ptr pFilter; while( nCurrent < m_rMatch.pList->size() ) { pFilter = (*m_rMatch.pList)[nCurrent++]; SfxFilterFlags nFlags = pFilter->GetFilterFlags(); if( ((nFlags & nOrMask) == nOrMask ) && !(nFlags & nAndMask ) ) break; pFilter = nullptr; } return pFilter; } std::shared_ptr SfxFilterMatcherIter::First() { nCurrent = 0; return Find_Impl(); } std::shared_ptr SfxFilterMatcherIter::Next() { return Find_Impl(); } /*--------------------------------------------------------------- helper to build own formatted string from given stringlist by using given separator ---------------------------------------------------------------*/ static OUString implc_convertStringlistToString( const uno::Sequence< OUString >& lList , sal_Unicode cSeparator, std::u16string_view sPrefix ) { OUStringBuffer sString ( 1000 ) ; sal_Int32 nCount = lList.getLength(); sal_Int32 nItem = 0 ; for( nItem=0; nItem& xTypeCFG, const uno::Reference< container::XNameAccess >& xFilterCFG, bool bUpdate ) { OUString sFilterName( rName ); SfxFilterList_Impl& rList = *pFilterArr; uno::Sequence< beans::PropertyValue > lFilterProperties; uno::Any aResult; try { aResult = xFilterCFG->getByName( sFilterName ); } catch( container::NoSuchElementException& ) { aResult = uno::Any(); } if( !(aResult >>= lFilterProperties) ) return; // collect information to add filter to container // (attention: some information aren't available on filter directly ... you must search for corresponding type too!) SfxFilterFlags nFlags = SfxFilterFlags::NONE; SotClipboardFormatId nClipboardId = SotClipboardFormatId::NONE; sal_Int32 nFormatVersion = 0 ; OUString sMimeType ; OUString sType ; OUString sUIName ; OUString sHumanName ; OUString sDefaultTemplate ; OUString sUserData ; OUString sExtension ; OUString sServiceName ; bool bEnabled = true ; // first get directly available properties for( const auto& rFilterProperty : std::as_const(lFilterProperties) ) { if ( rFilterProperty.Name == "FileFormatVersion" ) { rFilterProperty.Value >>= nFormatVersion; } else if ( rFilterProperty.Name == "TemplateName" ) { rFilterProperty.Value >>= sDefaultTemplate; } else if ( rFilterProperty.Name == "Flags" ) { sal_Int32 nTmp(0); rFilterProperty.Value >>= nTmp; assert((nTmp & ~o3tl::typed_flags::mask) == 0); nFlags = static_cast(nTmp); } else if ( rFilterProperty.Name == "UIName" ) { rFilterProperty.Value >>= sUIName; } else if ( rFilterProperty.Name == "UserData" ) { uno::Sequence< OUString > lUserData; rFilterProperty.Value >>= lUserData; sUserData = implc_convertStringlistToString( lUserData, ',', u"" ); } else if ( rFilterProperty.Name == "DocumentService" ) { rFilterProperty.Value >>= sServiceName; } else if (rFilterProperty.Name == "ExportExtension") { // Extension preferred by the filter. This takes precedence // over those that are given in the file format type. rFilterProperty.Value >>= sExtension; sExtension = "*." + sExtension; } else if ( rFilterProperty.Name == "Type" ) { rFilterProperty.Value >>= sType; // Try to get filter .. but look for any exceptions! // May be filter was deleted by another thread ... try { aResult = xTypeCFG->getByName( sType ); } catch (const container::NoSuchElementException&) { aResult = uno::Any(); } uno::Sequence< beans::PropertyValue > lTypeProperties; if( aResult >>= lTypeProperties ) { // get indirect available properties then (types) for( const auto& rTypeProperty : std::as_const(lTypeProperties) ) { if ( rTypeProperty.Name == "ClipboardFormat" ) { rTypeProperty.Value >>= sHumanName; } else if ( rTypeProperty.Name == "MediaType" ) { rTypeProperty.Value >>= sMimeType; } else if ( rTypeProperty.Name == "Extensions" ) { if (sExtension.isEmpty()) { uno::Sequence< OUString > lExtensions; rTypeProperty.Value >>= lExtensions; sExtension = implc_convertStringlistToString( lExtensions, ';', u"*." ); } } } } } else if ( rFilterProperty.Name == "Enabled" ) { rFilterProperty.Value >>= bEnabled; } } if ( sServiceName.isEmpty() ) return; // old formats are found ... using HumanPresentableName! if( !sHumanName.isEmpty() ) { nClipboardId = SotExchange::RegisterFormatName( sHumanName ); // For external filters ignore clipboard IDs if(nFlags & SfxFilterFlags::STARONEFILTER) { nClipboardId = SotClipboardFormatId::NONE; } } // register SfxFilter // first erase module name from old filter names! // e.g: "scalc: DIF" => "DIF" sal_Int32 nStartRealName = sFilterName.indexOf( ": " ); if( nStartRealName != -1 ) { SAL_WARN( "sfx.bastyp", "Old format, not supported!"); sFilterName = sFilterName.copy( nStartRealName+2 ); } std::shared_ptr pFilter = bUpdate ? SfxFilter::GetFilterByName( sFilterName ) : nullptr; if (!pFilter) { pFilter = std::make_shared( sFilterName , sExtension , nFlags , nClipboardId , sType , sMimeType , sUserData , sServiceName , bEnabled ); rList.push_back( pFilter ); } else { SfxFilter* pFilt = const_cast(pFilter.get()); pFilt->maFilterName = sFilterName; pFilt->aWildCard = WildCard(sExtension, ';'); pFilt->nFormatType = nFlags; pFilt->lFormat = nClipboardId; pFilt->aTypeName = sType; pFilt->aMimeType = sMimeType; pFilt->aUserData = sUserData; pFilt->aServiceName = sServiceName; pFilt->mbEnabled = bEnabled; } SfxFilter* pFilt = const_cast(pFilter.get()); // Don't forget to set right UIName! // Otherwise internal name is used as fallback ... pFilt->SetUIName( sUIName ); pFilt->SetDefaultTemplate( sDefaultTemplate ); if( nFormatVersion ) { pFilt->SetVersion( nFormatVersion ); } } void SfxFilterContainer::ReadFilters_Impl( bool bUpdate ) { if ( !pFilterArr ) CreateFilterArr(); bFirstRead = false; SfxFilterList_Impl& rList = *pFilterArr; try { // get the FilterFactory service to access the registered filters ... and types! uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory(); uno::Reference< container::XNameAccess > xFilterCFG ; uno::Reference< container::XNameAccess > xTypeCFG ; if( xServiceManager.is() ) { xFilterCFG.set( xServiceManager->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY ); xTypeCFG.set( xServiceManager->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY ); } if( xFilterCFG.is() && xTypeCFG.is() ) { // select right query to get right set of filters for search module const uno::Sequence< OUString > lFilterNames = xFilterCFG->getElementNames(); if ( lFilterNames.hasElements() ) { // If list of filters already exist ... // ReadExternalFilters must work in update mode. // Best way seems to mark all filters NOT_INSTALLED // and change it back for all valid filters afterwards. if( !rList.empty() ) { bUpdate = true; for (const std::shared_ptr& pFilter : rList) { SfxFilter* pNonConstFilter = const_cast(pFilter.get()); pNonConstFilter->nFormatType |= SFX_FILTER_NOTINSTALLED; } } // get all properties of filters ... put it into the filter container for( const OUString& sFilterName : lFilterNames ) { // Try to get filter .. but look for any exceptions! // May be filter was deleted by another thread ... ReadSingleFilter_Impl( sFilterName, xTypeCFG, xFilterCFG, bUpdate ); } } } } catch(const uno::Exception&) { SAL_WARN( "sfx.bastyp", "SfxFilterContainer::ReadFilter()\nException detected. Possible not all filters could be cached." ); } if ( bUpdate ) { // global filter array was modified, factory specific ones might need an // update too for (const auto& aImpl : aImplArr) aImpl->Update(); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */