summaryrefslogtreecommitdiffstats
path: root/filter/source/config/cache/filterfactory.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'filter/source/config/cache/filterfactory.cxx')
-rw-r--r--filter/source/config/cache/filterfactory.cxx498
1 files changed, 498 insertions, 0 deletions
diff --git a/filter/source/config/cache/filterfactory.cxx b/filter/source/config/cache/filterfactory.cxx
new file mode 100644
index 000000000..e083614c0
--- /dev/null
+++ b/filter/source/config/cache/filterfactory.cxx
@@ -0,0 +1,498 @@
+/* -*- 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 "filterfactory.hxx"
+#include "constant.hxx"
+
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <comphelper/enumhelper.hxx>
+#include <comphelper/sequence.hxx>
+#include <officecfg/Setup.hxx>
+#include <officecfg/TypeDetection/UISort.hxx>
+
+
+namespace filter::config{
+
+FilterCache& GetTheFilterCache()
+{
+ static FilterCache CACHE;
+ return CACHE;
+}
+
+/** @short define all possible parts of a filter query.
+
+ @descr syntax: "<query>[:<param>[=<value>]]"
+ e.g.: "_query_writer:default_first:use_order:sort_prop=uiname"
+
+ argument description default
+ -----------------------------------------------------------------------------------------------
+ iflags=<mask> include filters by given mask 0
+ eflags=<mask> exclude filters by given mask 0
+ sort_prop=<[name,uiname]> sort by internal name or uiname name
+ descending sort descending false
+ use_order use order flag of filters for sorting false
+ default_first set default filter on top of return list false
+ case_sensitive compare "sort_prop" case sensitive false
+ */
+
+FilterFactory::FilterFactory(const css::uno::Reference< css::uno::XComponentContext >& rxContext)
+ : m_xContext(rxContext)
+{
+ static const css::uno::Sequence<OUString> sServiceNames { "com.sun.star.document.FilterFactory" };
+ BaseContainer::init("com.sun.star.comp.filter.config.FilterFactory" ,
+ sServiceNames,
+ FilterCache::E_FILTER );
+}
+
+
+FilterFactory::~FilterFactory()
+{
+}
+
+
+css::uno::Reference< css::uno::XInterface > SAL_CALL FilterFactory::createInstance(const OUString& sFilter)
+{
+ return createInstanceWithArguments(sFilter, css::uno::Sequence< css::uno::Any >());
+}
+
+
+css::uno::Reference< css::uno::XInterface > SAL_CALL FilterFactory::createInstanceWithArguments(const OUString& sFilter ,
+ const css::uno::Sequence< css::uno::Any >& lArguments)
+{
+ // SAFE ->
+ osl::MutexGuard aLock(m_aMutex);
+
+ auto & cache = GetTheFilterCache();
+
+ // search filter on cache
+ CacheItem aFilter = cache.getItem(FilterCache::E_FILTER, sFilter);
+ OUString sFilterService;
+ aFilter[PROPNAME_FILTERSERVICE] >>= sFilterService;
+
+ // create service instance
+ css::uno::Reference< css::uno::XInterface > xFilter;
+ if (!sFilterService.isEmpty())
+ xFilter = m_xContext->getServiceManager()->createInstanceWithContext(sFilterService, m_xContext);
+
+ // initialize filter
+ css::uno::Reference< css::lang::XInitialization > xInit(xFilter, css::uno::UNO_QUERY);
+ if (xInit.is())
+ {
+ // format: lInitData[0] = seq<PropertyValue>, which contains all configuration properties of this filter
+ // lInitData[1] = lArguments[0]
+ // ...
+ // lInitData[n] = lArguments[n-1]
+ css::uno::Sequence< css::beans::PropertyValue > lConfig;
+ aFilter >> lConfig;
+
+ ::std::vector< css::uno::Any > stlArguments(comphelper::sequenceToContainer< ::std::vector< css::uno::Any > >(lArguments));
+ stlArguments.insert(stlArguments.begin(), css::uno::Any(lConfig));
+
+ xInit->initialize(comphelper::containerToSequence(stlArguments));
+ }
+
+ return xFilter;
+ // <- SAFE
+}
+
+
+css::uno::Sequence< OUString > SAL_CALL FilterFactory::getAvailableServiceNames()
+{
+ /* Attention: Instead of getElementNames() this method have to return only filter names,
+ which can be created as UNO Services really. That's why we search for filters,
+ which don't have a valid value for the property "FilterService".
+ Of course we can't check for corrupted service names here. We can check
+ for empty strings only...
+ */
+ css::beans::NamedValue lEProps[] {
+ { PROPNAME_FILTERSERVICE, css::uno::Any(OUString()) } };
+
+ std::vector<OUString> lUNOFilters;
+ try
+ {
+ lUNOFilters = GetTheFilterCache().getMatchingItemsByProps(FilterCache::E_FILTER, {}, lEProps);
+ }
+ catch(const css::uno::RuntimeException&)
+ { throw; }
+ catch(const css::uno::Exception&)
+ { lUNOFilters.clear(); }
+
+ return comphelper::containerToSequence(lUNOFilters);
+}
+
+
+css::uno::Reference< css::container::XEnumeration > SAL_CALL FilterFactory::createSubSetEnumerationByQuery(const OUString& sQuery)
+{
+ // reject old deprecated queries ...
+ if (sQuery.startsWith("_filterquery_"))
+ throw css::uno::RuntimeException(
+ "Use of deprecated and now unsupported query!",
+ static_cast< css::container::XContainerQuery* >(this));
+
+ // convert "_query_xxx:..." to "getByDocService=xxx:..."
+ OUString sNewQuery(sQuery);
+ sal_Int32 pos = sNewQuery.indexOf("_query_");
+ if (pos != -1)
+ {
+ OSL_FAIL("DEPRECATED!\nPlease use new query format: 'matchByDocumentService=...'");
+ OUString sPatchedQuery(OUString::Concat("matchByDocumentService=") + sNewQuery.subView(7));
+ sNewQuery = sPatchedQuery;
+ }
+
+ // analyze query and split it into its tokens
+ QueryTokenizer lTokens(sNewQuery);
+ std::vector<OUString> lEnumSet;
+
+ // start query
+ // (see attention comment below!)
+ if (lTokens.valid())
+ {
+ // SAFE -> ----------------------
+ {
+ osl::MutexGuard aLock(m_aMutex);
+ // May be not all filters was loaded ...
+ // But we need it now!
+ impl_loadOnDemand();
+ }
+ // <- SAFE ----------------------
+
+ if (lTokens.find(QUERY_IDENTIFIER_GETPREFERREDFILTERFORTYPE) != lTokens.end())
+ OSL_FAIL("DEPRECATED!\nPlease use prop search at the TypeDetection container!");
+ else
+ if (lTokens.find(QUERY_IDENTIFIER_MATCHBYDOCUMENTSERVICE) != lTokens.end())
+ lEnumSet = impl_queryMatchByDocumentService(lTokens);
+ else
+ if (lTokens.find(QUERY_IDENTIFIER_GET_SORTED_FILTERLIST) != lTokens.end())
+ lEnumSet = impl_getSortedFilterList(lTokens);
+ }
+
+ // pack list of item names as an enum list
+ // Attention: Do not return empty reference for empty list!
+ // The outside check "hasMoreElements()" should be enough, to detect this state :-)
+ return new ::comphelper::OEnumerationByName(this, std::move(lEnumSet));
+}
+
+
+std::vector<OUString> FilterFactory::impl_queryMatchByDocumentService(const QueryTokenizer& lTokens) const
+{
+ // analyze query
+ QueryTokenizer::const_iterator pIt;
+
+ OUString sDocumentService;
+ sal_Int32 nIFlags = 0;
+ sal_Int32 nEFlags = 0;
+
+ pIt = lTokens.find(QUERY_IDENTIFIER_MATCHBYDOCUMENTSERVICE);
+ if (pIt != lTokens.end())
+ sDocumentService = pIt->second;
+
+#define COMP_HACK
+#ifdef COMP_HACK
+ if ( sDocumentService == "writer" )
+ {
+ OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!");
+ sDocumentService = "com.sun.star.text.TextDocument";
+ }
+ else if ( sDocumentService == "web" )
+ {
+ OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!");
+ sDocumentService = "com.sun.star.text.WebDocument";
+ }
+ else if ( sDocumentService == "global" )
+ {
+ OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!");
+ sDocumentService = "com.sun.star.text.GlobalDocument";
+ }
+ else if ( sDocumentService == "calc" )
+ {
+ OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!");
+ sDocumentService = "com.sun.star.sheet.SpreadsheetDocument";
+ }
+ else if ( sDocumentService == "draw" )
+ {
+ OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!");
+ sDocumentService = "com.sun.star.drawing.DrawingDocument";
+ }
+ else if ( sDocumentService == "impress" )
+ {
+ OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!");
+ sDocumentService = "com.sun.star.presentation.PresentationDocument";
+ }
+ else if ( sDocumentService == "math" )
+ {
+ OSL_FAIL("DEPRECATED!\nPlease use right document service for filter query!");
+ sDocumentService = "com.sun.star.formula.FormulaProperties";
+ }
+#endif
+
+ pIt = lTokens.find(QUERY_PARAM_IFLAGS);
+ if (pIt != lTokens.end())
+ nIFlags = pIt->second.toInt32();
+
+ pIt = lTokens.find(QUERY_PARAM_EFLAGS);
+ if (pIt != lTokens.end())
+ nEFlags = pIt->second.toInt32();
+
+ // SAFE -> ----------------------
+ osl::ClearableMutexGuard aLock(m_aMutex);
+
+ // search suitable filters
+ FilterCache* pCache = impl_getWorkingCache();
+ std::vector<OUString> lFilterNames = pCache->getItemNames(FilterCache::E_FILTER);
+ std::vector<OUString> lResult ;
+
+ for (auto const& filterName : lFilterNames)
+ {
+ try
+ {
+ const CacheItem aFilter = pCache->getItem(FilterCache::E_FILTER, filterName);
+
+ // "matchByDocumentService=" => any filter will be addressed here
+ // "matchByDocumentService=all" => any filter will be addressed here
+ // "matchByDocumentService=com.sun.star..." => only filter matching this document service will be addressed
+ OUString sCheckValue = aFilter.getUnpackedValueOrDefault(PROPNAME_DOCUMENTSERVICE, OUString());
+ if (
+ (!sDocumentService.isEmpty() ) &&
+ (sDocumentService != QUERY_CONSTVALUE_ALL ) &&
+ (sCheckValue != sDocumentService )
+ )
+ {
+ continue; // ignore filter -> try next one!
+ }
+
+ // "iflags=" => not allowed
+ // "iflags=-1" => not allowed
+ // "iflags=0" => not useful
+ // "iflags=283648" => only filter, which has set these flag field will be addressed
+ sal_Int32 nCheckValue = aFilter.getUnpackedValueOrDefault(PROPNAME_FLAGS, sal_Int32(0));
+ if (
+ (nIFlags > 0 ) &&
+ ((nCheckValue & nIFlags) != nIFlags)
+ )
+ {
+ continue; // ignore filter -> try next one!
+ }
+
+ // "eflags=" => not allowed
+ // "eflags=-1" => not allowed
+ // "eflags=0" => not useful
+ // "eflags=283648" => only filter, which has not set these flag field will be addressed
+ if (
+ (nEFlags > 0 ) &&
+ ((nCheckValue & nEFlags) == nEFlags)
+ )
+ {
+ continue; // ignore filter -> try next one!
+ }
+
+ // OK - this filter passed all checks.
+ // It match the query ...
+ lResult.push_back(filterName);
+ }
+ catch(const css::uno::RuntimeException&)
+ { throw; }
+ catch(const css::uno::Exception&)
+ { continue; }
+ }
+
+ aLock.clear();
+ // <- SAFE ----------------------
+
+ return lResult;
+}
+
+namespace {
+
+class stlcomp_removeIfMatchFlags
+{
+ private:
+ FilterCache* m_pCache ;
+ sal_Int32 m_nFlags ;
+ bool m_bIFlags;
+
+ public:
+ stlcomp_removeIfMatchFlags(FilterCache* pCache ,
+ sal_Int32 nFlags ,
+ bool bIFlags)
+ : m_pCache (pCache )
+ , m_nFlags (nFlags )
+ , m_bIFlags(bIFlags)
+ {}
+
+ bool operator() (const OUString& sFilter) const
+ {
+ try
+ {
+ const CacheItem aFilter = m_pCache->getItem(FilterCache::E_FILTER, sFilter);
+ sal_Int32 nFlags = aFilter.getUnpackedValueOrDefault(PROPNAME_FLAGS, (sal_Int32(0)));
+
+ bool bMatch = false;
+ if (m_bIFlags)
+ // IFlags are interpreted as ALL_FLAGS_MUST_MATCH !
+ bMatch = ((nFlags & m_nFlags) == m_nFlags);
+ else
+ // EFlags are interpreted as AT_LEAST_ONE_FLAG_MUST_MATCH !
+ bMatch = !(nFlags & m_nFlags);
+ // We are asked for bRemove ! And bMatch = !bRemove => so bRemove = !bMatch .-)
+ return !bMatch;
+ }
+ catch(const css::container::NoSuchElementException &)
+ {
+ return true;
+ }
+ }
+};
+
+}
+
+std::vector<OUString> FilterFactory::impl_getSortedFilterList(const QueryTokenizer& lTokens) const
+{
+ // analyze the given query parameter
+ QueryTokenizer::const_iterator pIt1;
+
+ OUString sModule;
+ sal_Int32 nIFlags = -1;
+ sal_Int32 nEFlags = -1;
+
+ pIt1 = lTokens.find(QUERY_PARAM_MODULE);
+ if (pIt1 != lTokens.end())
+ sModule = pIt1->second;
+ pIt1 = lTokens.find(QUERY_PARAM_IFLAGS);
+ if (pIt1 != lTokens.end())
+ nIFlags = pIt1->second.toInt32();
+ pIt1 = lTokens.find(QUERY_PARAM_EFLAGS);
+ if (pIt1 != lTokens.end())
+ nEFlags = pIt1->second.toInt32();
+
+ // simple search for filters of one specific module.
+ std::vector<OUString> lFilterList;
+ if (!sModule.isEmpty())
+ lFilterList = impl_getSortedFilterListForModule(sModule, nIFlags, nEFlags);
+ else
+ {
+ // more complex search for all filters
+ // We check first, which office modules are installed...
+ const css::uno::Sequence<OUString> lModules = impl_getListOfInstalledModules();
+ for (auto const& module : lModules)
+ {
+ std::vector<OUString> lFilters4Module = impl_getSortedFilterListForModule(module, nIFlags, nEFlags);
+ for (auto const& filter4Module : lFilters4Module)
+ {
+ lFilterList.push_back(filter4Module);
+ }
+ }
+ }
+
+ return lFilterList;
+}
+
+
+css::uno::Sequence<OUString> FilterFactory::impl_getListOfInstalledModules()
+{
+ css::uno::Reference< css::container::XNameAccess > xModuleConfig = officecfg::Setup::Office::Factories::get();
+ return xModuleConfig->getElementNames();
+}
+
+
+std::vector<OUString> FilterFactory::impl_getSortedFilterListForModule(const OUString& sModule,
+ sal_Int32 nIFlags,
+ sal_Int32 nEFlags) const
+{
+ std::vector<OUString> lSortedFilters = impl_readSortedFilterListFromConfig(sModule);
+
+ // get all filters for the requested module
+ css::beans::NamedValue lIProps[] { { PROPNAME_DOCUMENTSERVICE, css::uno::Any(sModule) } };
+
+ // SAFE -> ----------------------
+ osl::ClearableMutexGuard aLock(m_aMutex);
+ FilterCache* pCache = impl_getWorkingCache();
+ std::vector<OUString> lOtherFilters = pCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps);
+ aLock.clear();
+ // <- SAFE ----------------------
+
+ // bring "other" filters in an alphabetical order
+ // It's needed below.
+ ::std::sort(lOtherFilters.begin(), lOtherFilters.end());
+
+ // merge both lists together
+ std::vector<OUString> lMergedFilters = lSortedFilters;
+ const auto itlSortedFiltersEnd = lSortedFilters.cend();
+ for (auto const& otherFilter : lOtherFilters)
+ {
+ if (::std::find(lSortedFilters.cbegin(), lSortedFilters.cend(), otherFilter) == itlSortedFiltersEnd)
+ lMergedFilters.push_back(otherFilter);
+ }
+
+ // remove all filters from this merged list, which does not fit the flag specification
+ if (nIFlags != -1)
+ {
+ auto pItToErase = ::std::remove_if(lMergedFilters.begin(), lMergedFilters.end(), stlcomp_removeIfMatchFlags(pCache, nIFlags, true));
+ lMergedFilters.erase(pItToErase, lMergedFilters.end());
+ }
+ if (nEFlags != -1)
+ {
+ auto pItToErase = ::std::remove_if(lMergedFilters.begin(), lMergedFilters.end(), stlcomp_removeIfMatchFlags(pCache, nEFlags, false));
+ lMergedFilters.erase(pItToErase, lMergedFilters.end());
+ }
+
+ // sort the default filter to the front of this list
+ // TODO
+
+ return lMergedFilters;
+}
+
+
+std::vector<OUString> FilterFactory::impl_readSortedFilterListFromConfig(const OUString& sModule)
+{
+ try
+ {
+ css::uno::Reference< css::container::XNameAccess > xUISortConfig = officecfg::TypeDetection::UISort::ModuleDependendFilterOrder::get();
+ // don't check the module name here. If it does not exists, an exception is thrown and caught below.
+ // We return an empty list as result then.
+ css::uno::Reference< css::container::XNameAccess > xModule;
+ xUISortConfig->getByName(sModule) >>= xModule;
+ if (xModule.is()) // only to be on the safe side of life if the exception was not thrown .-)
+ {
+ // Note: conversion of the returned Any to std::vector<OUString> throws
+ // an IllegalArgumentException if the type does not match ...
+ // but it resets the std::vector<OUString> to a length of 0 if the Any is empty!
+ std::vector<OUString> lSortedFilters(
+ comphelper::sequenceToContainer< std::vector<OUString> >(xModule->getByName(PROPNAME_SORTEDFILTERLIST).get<css::uno::Sequence<OUString> >()));
+ return lSortedFilters;
+ }
+ }
+ catch(const css::uno::RuntimeException&)
+ { throw; }
+ catch(const css::uno::Exception&)
+ {}
+
+ return std::vector<OUString>();
+}
+
+} // namespace filter
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+filter_FilterFactory_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new filter::config::FilterFactory(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */