android: Update app-specific/MIME type icons
[LibreOffice.git] / filter / source / config / cache / filtercache.cxx
blobaa0eff534cb48a574f18942128495b057660638b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <memory>
22 #include <comphelper/diagnose_ex.hxx>
23 #include "filtercache.hxx"
24 #include "constant.hxx"
25 #include "cacheupdatelistener.hxx"
27 /*TODO see using below ... */
28 #define AS_ENABLE_FILTER_UINAMES
30 #include <com/sun/star/configuration/theDefaultProvider.hpp>
31 #include <com/sun/star/util/XChangesBatch.hpp>
32 #include <com/sun/star/container/XNameContainer.hpp>
33 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
34 #include <com/sun/star/beans/NamedValue.hpp>
35 #include <com/sun/star/beans/XMultiPropertySet.hpp>
36 #include <com/sun/star/beans/XProperty.hpp>
37 #include <com/sun/star/beans/PropertyValue.hpp>
38 #include <com/sun/star/beans/Property.hpp>
39 #include <com/sun/star/beans/PropertyAttribute.hpp>
40 #include <com/sun/star/document/CorruptedFilterConfigurationException.hpp>
41 #include <comphelper/sequence.hxx>
42 #include <comphelper/processfactory.hxx>
44 #include <unotools/configmgr.hxx>
45 #include <unotools/configpaths.hxx>
46 #include <rtl/ustrbuf.hxx>
47 #include <rtl/uri.hxx>
48 #include <sal/log.hxx>
49 #include <tools/urlobj.hxx>
50 #include <tools/wldcrd.hxx>
51 #include <i18nlangtag/languagetag.hxx>
53 #include <officecfg/Setup.hxx>
54 #include <o3tl/string_view.hxx>
57 namespace filter::config{
59 FilterCache::FilterCache()
60 : m_eFillState(E_CONTAINS_NOTHING )
62 int i = 0;
63 OUString sStandardProps[10];
65 sStandardProps[i++] = PROPNAME_USERDATA;
66 sStandardProps[i++] = PROPNAME_TEMPLATENAME;
67 sStandardProps[i++] = PROPNAME_ENABLED;
68 // E_READ_UPDATE only above
69 sStandardProps[i++] = PROPNAME_TYPE;
70 sStandardProps[i++] = PROPNAME_FILEFORMATVERSION;
71 sStandardProps[i++] = PROPNAME_UICOMPONENT;
72 sStandardProps[i++] = PROPNAME_FILTERSERVICE;
73 sStandardProps[i++] = PROPNAME_DOCUMENTSERVICE;
74 sStandardProps[i++] = PROPNAME_EXPORTEXTENSION;
75 sStandardProps[i++] = PROPNAME_FLAGS; // must be last.
76 assert(i == SAL_N_ELEMENTS(sStandardProps));
78 // E_READ_NOTHING -> creative nothingness.
79 m_aStandardProps[E_READ_STANDARD] =
80 css::uno::Sequence< OUString >(sStandardProps + 3, 7);
81 m_aStandardProps[E_READ_UPDATE] =
82 css::uno::Sequence< OUString >(sStandardProps, 3);
83 m_aStandardProps[E_READ_ALL] =
84 css::uno::Sequence< OUString >(sStandardProps,
85 SAL_N_ELEMENTS(sStandardProps));
87 i = 0;
88 OUString sTypeProps[7];
89 sTypeProps[i++] = PROPNAME_MEDIATYPE;
90 // E_READ_UPDATE only above
91 sTypeProps[i++] = PROPNAME_PREFERREDFILTER;
92 sTypeProps[i++] = PROPNAME_DETECTSERVICE;
93 sTypeProps[i++] = PROPNAME_URLPATTERN;
94 sTypeProps[i++] = PROPNAME_EXTENSIONS;
95 sTypeProps[i++] = PROPNAME_PREFERRED;
96 sTypeProps[i++] = PROPNAME_CLIPBOARDFORMAT;
97 assert(i == SAL_N_ELEMENTS(sTypeProps));
99 // E_READ_NOTHING -> more creative nothingness.
100 m_aTypeProps[E_READ_STANDARD] =
101 css::uno::Sequence< OUString >(sTypeProps + 1, 6);
102 m_aTypeProps[E_READ_UPDATE] =
103 css::uno::Sequence< OUString >(sTypeProps, 1);
104 m_aTypeProps[E_READ_ALL] =
105 css::uno::Sequence< OUString >(sTypeProps,
106 SAL_N_ELEMENTS(sTypeProps));
110 FilterCache::~FilterCache()
112 if (m_xTypesChglisteners.is())
113 m_xTypesChglisteners->stopListening();
114 if (m_xFiltersChgListener.is())
115 m_xFiltersChgListener->stopListening();
119 std::unique_ptr<FilterCache> FilterCache::clone() const
121 // SAFE -> ----------------------------------
122 std::unique_lock aGuard(m_aMutex);
124 auto pClone = std::make_unique<FilterCache>();
126 // Don't copy the configuration access points here.
127 // They will be created on demand inside the cloned instance,
128 // if they are needed.
130 pClone->m_lTypes = m_lTypes;
131 pClone->m_lFilters = m_lFilters;
132 pClone->m_lFrameLoaders = m_lFrameLoaders;
133 pClone->m_lContentHandlers = m_lContentHandlers;
134 pClone->m_lExtensions2Types = m_lExtensions2Types;
135 pClone->m_lURLPattern2Types = m_lURLPattern2Types;
137 pClone->m_sActLocale = m_sActLocale;
139 pClone->m_eFillState = m_eFillState;
141 pClone->m_lChangedTypes = m_lChangedTypes;
142 pClone->m_lChangedFilters = m_lChangedFilters;
143 pClone->m_lChangedFrameLoaders = m_lChangedFrameLoaders;
144 pClone->m_lChangedContentHandlers = m_lChangedContentHandlers;
146 return pClone;
147 // <- SAFE ----------------------------------
151 void FilterCache::takeOver(const FilterCache& rClone)
153 // SAFE -> ----------------------------------
154 std::unique_lock aGuard(m_aMutex);
156 // a)
157 // Don't copy the configuration access points here!
158 // We must use our own ones...
160 // b)
161 // Further we can ignore the uno service manager.
162 // We should already have a valid instance.
164 // c)
165 // Take over only changed items!
166 // Otherwise we risk the following scenario:
167 // c1) clone_1 contains changed filters
168 // c2) clone_2 container changed types
169 // c3) clone_1 take over changed filters and unchanged types
170 // c4) clone_2 take over unchanged filters(!) and changed types(!)
171 // c5) c4 overwrites c3!
173 if (!rClone.m_lChangedTypes.empty())
174 m_lTypes = rClone.m_lTypes;
175 if (!rClone.m_lChangedFilters.empty())
176 m_lFilters = rClone.m_lFilters;
177 if (!rClone.m_lChangedFrameLoaders.empty())
178 m_lFrameLoaders = rClone.m_lFrameLoaders;
179 if (!rClone.m_lChangedContentHandlers.empty())
180 m_lContentHandlers = rClone.m_lContentHandlers;
182 m_lChangedTypes.clear();
183 m_lChangedFilters.clear();
184 m_lChangedFrameLoaders.clear();
185 m_lChangedContentHandlers.clear();
187 m_sActLocale = rClone.m_sActLocale;
189 m_eFillState = rClone.m_eFillState;
191 // renew all dependencies and optimizations
192 // Because we can't be sure, that changed filters on one clone
193 // and changed types of another clone work together.
194 // But here we can check against the later changes...
195 impl_validateAndOptimize(aGuard);
196 // <- SAFE ----------------------------------
199 void FilterCache::load(EFillState eRequired)
201 // SAFE -> ----------------------------------
202 std::unique_lock aGuard(m_aMutex);
204 // check if required fill state is already reached ...
205 // There is nothing to do then.
206 if ((m_eFillState & eRequired) == eRequired)
207 return;
209 // Otherwise load the missing items.
212 // a) load some const values from configuration.
213 // These values are needed there for loading
214 // config items ...
215 // Further we load some std items from the
216 // configuration so we can try to load the first
217 // office document with a minimal set of values.
218 if (m_eFillState == E_CONTAINS_NOTHING)
220 impl_getDirectCFGValue(aGuard, CFGDIRECTKEY_OFFICELOCALE) >>= m_sActLocale;
221 if (m_sActLocale.isEmpty())
223 m_sActLocale = DEFAULT_OFFICELOCALE;
226 // Support the old configuration support. Read it only one times during office runtime!
227 impl_readOldFormat(aGuard);
231 // b) If the required fill state was not reached
232 // but std values was already loaded ...
233 // we must load some further missing items.
234 impl_load(aGuard, eRequired);
235 // <- SAFE
238 bool FilterCache::isFillState(FilterCache::EFillState eState) const
240 // SAFE ->
241 std::unique_lock aGuard(m_aMutex);
242 return ((m_eFillState & eState) == eState);
243 // <- SAFE
247 std::vector<OUString> FilterCache::getMatchingItemsByProps( EItemType eType ,
248 o3tl::span< const css::beans::NamedValue > lIProps,
249 o3tl::span< const css::beans::NamedValue > lEProps) const
251 // SAFE ->
252 std::unique_lock aGuard(m_aMutex);
254 // search for right list
255 // An exception is thrown - "eType" is unknown.
256 // => rList will be valid everytimes next line is reached.
257 const CacheItemList& rList = impl_getItemList(aGuard, eType);
259 std::vector<OUString> lKeys;
260 lKeys.reserve(rList.size());
262 // search items, which provides all needed properties of set "lIProps"
263 // but not of set "lEProps"!
264 for (auto const& elem : rList)
266 if (
267 (elem.second.haveProps(lIProps) ) &&
268 (elem.second.dontHaveProps(lEProps))
271 lKeys.push_back(elem.first);
275 return lKeys;
276 // <- SAFE
280 bool FilterCache::hasItems(EItemType eType) const
282 // SAFE ->
283 std::unique_lock aGuard(m_aMutex);
285 // search for right list
286 // An exception is thrown - "eType" is unknown.
287 // => rList will be valid everytimes next line is reached.
288 const CacheItemList& rList = impl_getItemList(aGuard, eType);
290 return !rList.empty();
291 // <- SAFE
295 std::vector<OUString> FilterCache::getItemNames(EItemType eType) const
297 // SAFE ->
298 std::unique_lock aGuard(m_aMutex);
299 return getItemNames(aGuard, eType);
300 // <- SAFE
303 std::vector<OUString> FilterCache::getItemNames(std::unique_lock<std::mutex>& rGuard, EItemType eType) const
305 // search for right list
306 // An exception is thrown - "eType" is unknown.
307 // => rList will be valid everytimes next line is reached.
308 const CacheItemList& rList = impl_getItemList(rGuard, eType);
310 std::vector<OUString> lKeys;
311 for (auto const& elem : rList)
313 lKeys.push_back(elem.first);
315 return lKeys;
319 bool FilterCache::hasItem( EItemType eType,
320 const OUString& sItem)
322 // SAFE ->
323 std::unique_lock aGuard(m_aMutex);
325 // search for right list
326 // An exception is thrown - "eType" is unknown.
327 // => rList will be valid everytimes next line is reached.
328 const CacheItemList& rList = impl_getItemList(aGuard, eType);
330 // if item could not be found - check if it can be loaded
331 // from the underlying configuration layer. Might it was not already
332 // loaded into this FilterCache object before.
333 CacheItemList::const_iterator pIt = rList.find(sItem);
334 if (pIt != rList.end())
335 return true;
339 impl_loadItemOnDemand(aGuard, eType, sItem);
340 // no exception => item could be loaded!
341 return true;
343 catch(const css::container::NoSuchElementException&)
346 return false;
347 // <- SAFE
351 CacheItem FilterCache::getItem( EItemType eType,
352 const OUString& sItem)
354 // SAFE ->
355 std::unique_lock aGuard(m_aMutex);
357 CacheItem aItem = impl_getItem(aGuard, eType, sItem);
358 // <- SAFE
359 return aItem;
363 CacheItem& FilterCache::impl_getItem( std::unique_lock<std::mutex>& rGuard,
364 EItemType eType,
365 const OUString& sItem)
367 // search for right list
368 // An exception is thrown if "eType" is unknown.
369 // => rList will be valid everytimes next line is reached.
370 CacheItemList& rList = impl_getItemList(rGuard, eType);
372 // check if item exists ...
373 CacheItemList::iterator pIt = rList.find(sItem);
374 if (pIt == rList.end())
376 // ... or load it on demand from the
377 // underlying configuration layer.
378 // Note: NoSuchElementException is thrown automatically here if
379 // item could not be loaded!
380 pIt = impl_loadItemOnDemand(rGuard, eType, sItem);
383 /* Workaround for #137955#
384 Draw types and filters are installed ... but draw was disabled during setup.
385 We must suppress accessing these filters. Otherwise the office can crash.
386 Solution for the next major release: do not install those filters !
388 if (eType == E_FILTER)
390 CacheItem& rFilter = pIt->second;
391 OUString sDocService;
392 rFilter[PROPNAME_DOCUMENTSERVICE] >>= sDocService;
394 // In Standalone-Impress the module WriterWeb is not installed
395 // but it is there to load help pages
396 bool bIsHelpFilter = sItem == "writer_web_HTML_help";
398 if ( !bIsHelpFilter && !impl_isModuleInstalled(rGuard, sDocService) )
400 OUString sMsg("The requested filter '" + sItem +
401 "' exists ... but it should not; because the corresponding LibreOffice module was not installed.");
402 throw css::container::NoSuchElementException(sMsg, css::uno::Reference< css::uno::XInterface >());
406 return pIt->second;
410 void FilterCache::removeItem( EItemType eType,
411 const OUString& sItem)
413 // SAFE ->
414 std::unique_lock aGuard(m_aMutex);
416 // search for right list
417 // An exception is thrown - "eType" is unknown.
418 // => rList will be valid everytimes next line is reached.
419 CacheItemList& rList = impl_getItemList(aGuard, eType);
421 CacheItemList::iterator pItem = rList.find(sItem);
422 if (pItem == rList.end())
423 pItem = impl_loadItemOnDemand(aGuard, eType, sItem); // throws NoSuchELementException!
424 rList.erase(pItem);
426 impl_addItem2FlushList(eType, sItem);
430 void FilterCache::setItem( EItemType eType ,
431 const OUString& sItem ,
432 const CacheItem& aValue)
434 // SAFE ->
435 std::unique_lock aGuard(m_aMutex);
437 // search for right list
438 // An exception is thrown - "eType" is unknown.
439 // => rList will be valid everytimes next line is reached.
440 CacheItemList& rList = impl_getItemList(aGuard, eType);
442 // name must be part of the property set too ... otherwise our
443 // container query can't work correctly
444 CacheItem aItem = aValue;
445 aItem[PROPNAME_NAME] <<= sItem;
446 aItem.validateUINames(m_sActLocale);
448 // remove implicit properties as e.g. FINALIZED or MANDATORY
449 // They can't be saved here and must be read on demand later, if they are needed.
450 removeStatePropsFromItem(aItem);
452 rList[sItem] = aItem;
454 impl_addItem2FlushList(eType, sItem);
458 void FilterCache::refreshItem( EItemType eType,
459 const OUString& sItem)
461 // SAFE ->
462 std::unique_lock aGuard(m_aMutex);
463 impl_loadItemOnDemand(aGuard, eType, sItem);
467 css::uno::Any FilterCache::getItemWithStateProps( EItemType eType,
468 const OUString& sItem)
470 // SAFE ->
471 std::unique_lock aGuard(m_aMutex);
473 const CacheItem& rItem = impl_getItem(aGuard, eType, sItem);
475 // Note: Opening of the configuration layer throws some exceptions
476 // if it failed. So we mustn't check any reference here...
477 css::uno::Reference< css::container::XNameAccess > xPackage;
478 css::uno::Reference< css::container::XNameAccess > xSet;
479 switch(eType)
481 case E_TYPE :
483 xPackage.set(impl_openConfig(aGuard, E_PROVIDER_TYPES), css::uno::UNO_QUERY_THROW);
484 xPackage->getByName(CFGSET_TYPES) >>= xSet;
486 break;
488 case E_FILTER :
490 xPackage.set(impl_openConfig(aGuard, E_PROVIDER_FILTERS), css::uno::UNO_QUERY_THROW);
491 xPackage->getByName(CFGSET_FILTERS) >>= xSet;
493 break;
495 case E_FRAMELOADER :
497 /* TODO
498 Hack -->
499 The default frame loader can't be located inside the normal set of frame loaders.
500 It's an atomic property inside the misc cfg package. So we can't retrieve the information
501 about FINALIZED and MANDATORY very easy ... :-(
502 => set it to readonly/required everytimes :-)
504 css::uno::Any aDirectValue = impl_getDirectCFGValue(aGuard, CFGDIRECTKEY_DEFAULTFRAMELOADER);
505 OUString sDefaultFrameLoader;
506 if (
507 (aDirectValue >>= sDefaultFrameLoader) &&
508 (!sDefaultFrameLoader.isEmpty() ) &&
509 (sItem == sDefaultFrameLoader )
512 css::uno::Sequence aProps = rItem.getAsPackedPropertyValueList(true, true);
513 return css::uno::Any(aProps);
515 /* <-- HACK */
517 xPackage.set(impl_openConfig(aGuard, E_PROVIDER_OTHERS), css::uno::UNO_QUERY_THROW);
518 xPackage->getByName(CFGSET_FRAMELOADERS) >>= xSet;
520 break;
522 case E_CONTENTHANDLER :
524 xPackage.set(impl_openConfig(aGuard, E_PROVIDER_OTHERS), css::uno::UNO_QUERY_THROW);
525 xPackage->getByName(CFGSET_CONTENTHANDLERS) >>= xSet;
527 break;
528 default: break;
531 bool bFinalized, bMandatory;
534 css::uno::Reference< css::beans::XProperty > xItem;
535 xSet->getByName(sItem) >>= xItem;
536 css::beans::Property aDescription = xItem->getAsProperty();
538 bFinalized = ((aDescription.Attributes & css::beans::PropertyAttribute::READONLY ) == css::beans::PropertyAttribute::READONLY );
539 bMandatory = ((aDescription.Attributes & css::beans::PropertyAttribute::REMOVABLE) != css::beans::PropertyAttribute::REMOVABLE);
542 catch(const css::container::NoSuchElementException&)
544 /* Ignore exceptions for missing elements inside configuration.
545 May by the following reason exists:
546 - The item does not exists inside the new configuration package org.openoffice.TypeDetection - but
547 we got it from the old package org.openoffice.Office/TypeDetection. We don't migrate such items
548 automatically to the new format. Because it will disturb e.g. the deinstallation of an external filter
549 package. Because such external filter can remove the old file - but not the automatically created new one ...
551 => mark item as FINALIZED / MANDATORY, we don't support writing to the old format
553 bFinalized = true;
554 bMandatory = true;
557 css::uno::Sequence<css::beans::PropertyValue> aProps = rItem.getAsPackedPropertyValueList(bFinalized, bMandatory);
559 return css::uno::Any(aProps);
560 // <- SAFE
564 void FilterCache::removeStatePropsFromItem(CacheItem& rItem)
566 CacheItem::iterator pIt = rItem.find(PROPNAME_FINALIZED);
567 if (pIt != rItem.end())
568 rItem.erase(pIt);
569 pIt = rItem.find(PROPNAME_MANDATORY);
570 if (pIt != rItem.end())
571 rItem.erase(pIt);
575 void FilterCache::flush()
577 // SAFE ->
578 std::unique_lock aGuard(m_aMutex);
580 // renew all dependencies and optimizations
581 impl_validateAndOptimize(aGuard);
583 if (!m_lChangedTypes.empty())
585 css::uno::Reference< css::container::XNameAccess > xConfig(impl_openConfig(aGuard, E_PROVIDER_TYPES), css::uno::UNO_QUERY_THROW);
586 css::uno::Reference< css::container::XNameAccess > xSet ;
588 xConfig->getByName(CFGSET_TYPES) >>= xSet;
589 impl_flushByList(xSet, E_TYPE, m_lTypes, m_lChangedTypes);
591 css::uno::Reference< css::util::XChangesBatch > xFlush(xConfig, css::uno::UNO_QUERY);
592 xFlush->commitChanges();
595 if (!m_lChangedFilters.empty())
597 css::uno::Reference< css::container::XNameAccess > xConfig(impl_openConfig(aGuard, E_PROVIDER_FILTERS), css::uno::UNO_QUERY_THROW);
598 css::uno::Reference< css::container::XNameAccess > xSet ;
600 xConfig->getByName(CFGSET_FILTERS) >>= xSet;
601 impl_flushByList(xSet, E_FILTER, m_lFilters, m_lChangedFilters);
603 css::uno::Reference< css::util::XChangesBatch > xFlush(xConfig, css::uno::UNO_QUERY);
604 xFlush->commitChanges();
607 /*TODO FrameLoader/ContentHandler must be flushed here too ... */
611 void FilterCache::impl_flushByList(const css::uno::Reference< css::container::XNameAccess >& xSet ,
612 EItemType eType ,
613 const CacheItemList& rCache,
614 const std::vector<OUString>& lItems)
616 css::uno::Reference< css::container::XNameContainer > xAddRemoveSet(xSet, css::uno::UNO_QUERY);
617 css::uno::Reference< css::lang::XSingleServiceFactory > xFactory(xSet, css::uno::UNO_QUERY);
619 for (auto const& item : lItems)
621 EItemFlushState eState = impl_specifyFlushOperation(xSet, rCache, item);
622 switch(eState)
624 case E_ITEM_REMOVED :
626 xAddRemoveSet->removeByName(item);
628 break;
630 case E_ITEM_ADDED :
632 css::uno::Reference< css::container::XNameReplace > xItem (xFactory->createInstance(), css::uno::UNO_QUERY);
634 // special case. no exception - but not a valid item => set must be finalized or mandatory!
635 // Reject flush operation by throwing an exception. At least one item couldn't be flushed.
636 if (!xItem.is())
637 throw css::uno::Exception("Can not add item. Set is finalized or mandatory!",
638 css::uno::Reference< css::uno::XInterface >());
640 CacheItemList::const_iterator pItem = rCache.find(item);
641 impl_saveItem(xItem, eType, pItem->second);
642 xAddRemoveSet->insertByName(item, css::uno::Any(xItem));
644 break;
646 case E_ITEM_CHANGED :
648 css::uno::Reference< css::container::XNameReplace > xItem;
649 xSet->getByName(item) >>= xItem;
651 // special case. no exception - but not a valid item => it must be finalized or mandatory!
652 // Reject flush operation by throwing an exception. At least one item couldn't be flushed.
653 if (!xItem.is())
654 throw css::uno::Exception("Can not change item. It's finalized or mandatory!",
655 css::uno::Reference< css::uno::XInterface >());
657 CacheItemList::const_iterator pItem = rCache.find(item);
658 impl_saveItem(xItem, eType, pItem->second);
660 break;
661 default: break;
667 void FilterCache::detectFlatForURL(const css::util::URL& aURL ,
668 FlatDetection& rFlatTypes) const
670 // extract extension from URL, so it can be used directly as key into our hash map!
671 // Note further: It must be converted to lower case, because the optimize hash
672 // (which maps extensions to types) work with lower case key strings!
673 INetURLObject aParser (aURL.Main);
674 OUString sExtension = aParser.getExtension(INetURLObject::LAST_SEGMENT ,
675 true ,
676 INetURLObject::DecodeMechanism::WithCharset);
677 sExtension = sExtension.toAsciiLowerCase();
679 // SAFE -> ----------------------------------
680 std::unique_lock aGuard(m_aMutex);
683 // i) Step over all well known URL pattern
684 // and add registered types to the return list too
685 // Do it as first one - because: if a type match by a
686 // pattern a following deep detection can be suppressed!
687 // Further we can stop after first match ...
688 for (auto const& pattern : m_lURLPattern2Types)
690 WildCard aPatternCheck(pattern.first);
691 if (aPatternCheck.Matches(aURL.Main))
693 const std::vector<OUString>& rTypesForPattern = pattern.second;
695 FlatDetectionInfo aInfo;
696 aInfo.sType = *(rTypesForPattern.begin());
697 aInfo.bMatchByPattern = true;
699 rFlatTypes.push_back(aInfo);
700 // return;
705 // ii) search types matching to the given extension.
706 // Copy every matching type without changing its order!
707 // Because preferred types was added as first one during
708 // loading configuration.
709 CacheItemRegistration::const_iterator pExtReg = m_lExtensions2Types.find(sExtension);
710 if (pExtReg != m_lExtensions2Types.end())
712 const std::vector<OUString>& rTypesForExtension = pExtReg->second;
713 for (auto const& elem : rTypesForExtension)
715 FlatDetectionInfo aInfo;
716 aInfo.sType = elem;
717 aInfo.bMatchByExtension = true;
719 rFlatTypes.push_back(aInfo);
723 // <- SAFE ----------------------------------
726 const CacheItemList& FilterCache::impl_getItemList(std::unique_lock<std::mutex>& /*rGuard*/, EItemType eType) const
728 switch(eType)
730 case E_TYPE : return m_lTypes ;
731 case E_FILTER : return m_lFilters ;
732 case E_FRAMELOADER : return m_lFrameLoaders ;
733 case E_CONTENTHANDLER : return m_lContentHandlers;
737 throw css::uno::RuntimeException("unknown sub container requested.",
738 css::uno::Reference< css::uno::XInterface >());
741 CacheItemList& FilterCache::impl_getItemList(std::unique_lock<std::mutex>& /*rGuard*/, EItemType eType)
743 switch(eType)
745 case E_TYPE : return m_lTypes ;
746 case E_FILTER : return m_lFilters ;
747 case E_FRAMELOADER : return m_lFrameLoaders ;
748 case E_CONTENTHANDLER : return m_lContentHandlers;
752 throw css::uno::RuntimeException("unknown sub container requested.",
753 css::uno::Reference< css::uno::XInterface >());
756 css::uno::Reference< css::uno::XInterface > FilterCache::impl_openConfig(std::unique_lock<std::mutex>& rGuard, EConfigProvider eProvider)
758 OUString sPath ;
759 css::uno::Reference< css::uno::XInterface >* pConfig = nullptr;
760 css::uno::Reference< css::uno::XInterface > xOld ;
761 OString sRtlLog ;
763 switch(eProvider)
765 case E_PROVIDER_TYPES :
767 if (m_xConfigTypes.is())
768 return m_xConfigTypes;
769 sPath = CFGPACKAGE_TD_TYPES;
770 pConfig = &m_xConfigTypes;
771 sRtlLog = "impl_openconfig(E_PROVIDER_TYPES)";
773 break;
775 case E_PROVIDER_FILTERS :
777 if (m_xConfigFilters.is())
778 return m_xConfigFilters;
779 sPath = CFGPACKAGE_TD_FILTERS;
780 pConfig = &m_xConfigFilters;
781 sRtlLog = "impl_openconfig(E_PROVIDER_FILTERS)";
783 break;
785 case E_PROVIDER_OTHERS :
787 if (m_xConfigOthers.is())
788 return m_xConfigOthers;
789 sPath = CFGPACKAGE_TD_OTHERS;
790 pConfig = &m_xConfigOthers;
791 sRtlLog = "impl_openconfig(E_PROVIDER_OTHERS)";
793 break;
795 case E_PROVIDER_OLD :
797 // This special provider is used to work with
798 // the old configuration format only. It's not cached!
799 sPath = CFGPACKAGE_TD_OLD;
800 pConfig = &xOld;
801 sRtlLog = "impl_openconfig(E_PROVIDER_OLD)";
803 break;
805 default : throw css::uno::RuntimeException("These configuration node is not supported here for open!", nullptr);
809 SAL_INFO( "filter.config", "" << sRtlLog);
810 *pConfig = impl_createConfigAccess(rGuard, sPath ,
811 false, // bReadOnly
812 true ); // bLocalesMode
816 // Start listening for changes on that configuration access.
817 switch(eProvider)
819 case E_PROVIDER_TYPES:
821 m_xTypesChglisteners.set(new CacheUpdateListener(*this, *pConfig, FilterCache::E_TYPE));
822 m_xTypesChglisteners->startListening();
824 break;
825 case E_PROVIDER_FILTERS:
827 m_xFiltersChgListener.set(new CacheUpdateListener(*this, *pConfig, FilterCache::E_FILTER));
828 m_xFiltersChgListener->startListening();
830 break;
831 default:
832 break;
835 return *pConfig;
838 css::uno::Any FilterCache::impl_getDirectCFGValue(std::unique_lock<std::mutex>& rGuard, std::u16string_view sDirectKey)
840 OUString sRoot;
841 OUString sKey ;
843 if (
844 (!::utl::splitLastFromConfigurationPath(sDirectKey, sRoot, sKey)) ||
845 (sRoot.isEmpty() ) ||
846 (sKey.isEmpty() )
848 return css::uno::Any();
850 css::uno::Reference< css::uno::XInterface > xCfg = impl_createConfigAccess(rGuard, sRoot ,
851 true , // bReadOnly
852 false); // bLocalesMode
853 if (!xCfg.is())
854 return css::uno::Any();
856 css::uno::Reference< css::container::XNameAccess > xAccess(xCfg, css::uno::UNO_QUERY);
857 if (!xAccess.is())
858 return css::uno::Any();
860 css::uno::Any aValue;
863 aValue = xAccess->getByName(sKey);
865 catch(const css::uno::RuntimeException&)
866 { throw; }
867 catch(const css::uno::Exception&)
869 TOOLS_WARN_EXCEPTION( "filter.config", "");
870 aValue.clear();
873 return aValue;
877 css::uno::Reference< css::uno::XInterface > FilterCache::impl_createConfigAccess(std::unique_lock<std::mutex>& /*rGuard*/,
878 const OUString& sRoot ,
879 bool bReadOnly ,
880 bool bLocalesMode)
882 css::uno::Reference< css::uno::XInterface > xCfg;
884 if (!utl::ConfigManager::IsFuzzing())
888 css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider(
889 css::configuration::theDefaultProvider::get( comphelper::getProcessComponentContext() ) );
891 ::std::vector< css::uno::Any > lParams;
892 css::beans::NamedValue aParam;
894 // set root path
895 aParam.Name = "nodepath";
896 aParam.Value <<= sRoot;
897 lParams.push_back(css::uno::Any(aParam));
899 // enable "all locales mode" ... if required
900 if (bLocalesMode)
902 aParam.Name = "locale";
903 aParam.Value <<= OUString("*");
904 lParams.push_back(css::uno::Any(aParam));
907 // open it
908 if (bReadOnly)
909 xCfg = xConfigProvider->createInstanceWithArguments(SERVICE_CONFIGURATIONACCESS,
910 comphelper::containerToSequence(lParams));
911 else
912 xCfg = xConfigProvider->createInstanceWithArguments(SERVICE_CONFIGURATIONUPDATEACCESS,
913 comphelper::containerToSequence(lParams));
915 // If configuration could not be opened... but factory method did not throw an exception
916 // trigger throwing of our own CorruptedFilterConfigurationException.
917 // Let message empty. The normal exception text show enough information to the user.
918 if (! xCfg.is())
919 throw css::uno::Exception(
920 "Got NULL reference on opening configuration file ... but no exception.",
921 css::uno::Reference< css::uno::XInterface >());
923 catch(const css::uno::Exception& ex)
925 throw css::document::CorruptedFilterConfigurationException(
926 "filter configuration, caught: " + ex.Message,
927 css::uno::Reference< css::uno::XInterface >(),
928 ex.Message);
932 return xCfg;
936 void FilterCache::impl_validateAndOptimize(std::unique_lock<std::mutex>& rGuard)
938 // First check if any filter or type could be read
939 // from the underlying configuration!
940 bool bSomeTypesShouldExist = ((m_eFillState & E_CONTAINS_STANDARD ) == E_CONTAINS_STANDARD );
941 bool bAllFiltersShouldExist = ((m_eFillState & E_CONTAINS_FILTERS ) == E_CONTAINS_FILTERS );
943 #if OSL_DEBUG_LEVEL > 0
945 sal_Int32 nWarnings = 0;
947 // sal_Bool bAllTypesShouldExist = ((m_eFillState & E_CONTAINS_TYPES ) == E_CONTAINS_TYPES );
948 bool bAllLoadersShouldExist = ((m_eFillState & E_CONTAINS_FRAMELOADERS ) == E_CONTAINS_FRAMELOADERS );
949 bool bAllHandlersShouldExist = ((m_eFillState & E_CONTAINS_CONTENTHANDLERS) == E_CONTAINS_CONTENTHANDLERS);
950 #endif
952 if (
954 bSomeTypesShouldExist && m_lTypes.empty()
955 ) ||
957 bAllFiltersShouldExist && m_lFilters.empty()
961 throw css::document::CorruptedFilterConfigurationException(
962 "filter configuration: the list of types or filters is empty",
963 css::uno::Reference< css::uno::XInterface >(),
964 "The list of types or filters is empty." );
967 // Create a log for all detected problems, which
968 // occur in the next few lines.
969 // If there are some real errors throw a RuntimException!
970 // If there are some warnings only, show an assertion.
971 sal_Int32 nErrors = 0;
972 OUStringBuffer sLog(256);
974 for (auto const& elem : m_lTypes)
976 const OUString & sType = elem.first;
977 const CacheItem & aType = elem.second;
979 // get its registration for file Extensions AND(!) URLPattern ...
980 // It doesn't matter if these items exists or if our
981 // used index access create some default ones ...
982 // only in case there is no filled set of Extensions AND
983 // no filled set of URLPattern -> we must try to remove this invalid item
984 // from this cache!
985 css::uno::Sequence< OUString > lExtensions;
986 css::uno::Sequence< OUString > lURLPattern;
987 auto it = aType.find(PROPNAME_EXTENSIONS);
988 if (it != aType.end())
989 it->second >>= lExtensions;
990 it = aType.find(PROPNAME_URLPATTERN);
991 if (it != aType.end())
992 it->second >>= lURLPattern;
993 sal_Int32 ce = lExtensions.getLength();
994 sal_Int32 cu = lURLPattern.getLength();
996 #if OSL_DEBUG_LEVEL > 0
998 OUString sInternalTypeNameCheck;
999 it = aType.find(PROPNAME_NAME);
1000 if (it != aType.end())
1001 it->second >>= sInternalTypeNameCheck;
1002 if (sInternalTypeNameCheck != sType)
1004 sLog.append("Warning\t:\t" "The type \"" + sType + "\" does support the property \"Name\" correctly.\n");
1005 ++nWarnings;
1008 if (!ce && !cu)
1010 sLog.append("Warning\t:\t" "The type \"" + sType + "\" does not contain any URL pattern nor any extensions.\n");
1011 ++nWarnings;
1013 #endif
1015 // create an optimized registration for this type to
1016 // its set list of extensions/url pattern. If it's a "normal" type
1017 // set it at the end of this optimized list. But if it's
1018 // a "Preferred" one - set it to the front of this list.
1019 // Of course multiple "Preferred" registrations can occur
1020 // (they shouldn't - but they can!) ... Ignore it. The last
1021 // preferred type is usable in the same manner then every
1022 // other type!
1023 bool bPreferred = false;
1024 it = aType.find(PROPNAME_PREFERRED);
1025 if (it != aType.end())
1026 it->second >>= bPreferred;
1028 const OUString* pExtensions = lExtensions.getConstArray();
1029 for (sal_Int32 e=0; e<ce; ++e)
1031 // Note: We must be sure that address the right hash entry
1032 // does not depend from any upper/lower case problems ...
1033 OUString sNormalizedExtension = pExtensions[e].toAsciiLowerCase();
1035 std::vector<OUString>& lTypesForExtension = m_lExtensions2Types[sNormalizedExtension];
1036 if (::std::find(lTypesForExtension.begin(), lTypesForExtension.end(), sType) != lTypesForExtension.end())
1037 continue;
1039 if (bPreferred)
1040 lTypesForExtension.insert(lTypesForExtension.begin(), sType);
1041 else
1042 lTypesForExtension.push_back(sType);
1045 const OUString* pURLPattern = lURLPattern.getConstArray();
1046 for (sal_Int32 u=0; u<cu; ++u)
1048 std::vector<OUString>& lTypesForURLPattern = m_lURLPattern2Types[pURLPattern[u]];
1049 if (::std::find(lTypesForURLPattern.begin(), lTypesForURLPattern.end(), sType) != lTypesForURLPattern.end())
1050 continue;
1052 if (bPreferred)
1053 lTypesForURLPattern.insert(lTypesForURLPattern.begin(), sType);
1054 else
1055 lTypesForURLPattern.push_back(sType);
1058 #if OSL_DEBUG_LEVEL > 0
1060 // Don't check cross references between types and filters, if
1061 // not all filters read from disk!
1062 // OK - this cache can read single filters on demand too ...
1063 // but then the fill state of this cache should not be set to E_CONTAINS_FILTERS!
1064 if (!bAllFiltersShouldExist)
1065 continue;
1067 OUString sPrefFilter;
1068 it = aType.find(PROPNAME_PREFERREDFILTER);
1069 if (it != aType.end())
1070 it->second >>= sPrefFilter;
1071 if (sPrefFilter.isEmpty())
1073 // OK - there is no filter for this type. But that's not an error.
1074 // Maybe it can be handled by a ContentHandler...
1075 // But at this time it's not guaranteed that there is any ContentHandler
1076 // or FrameLoader inside this cache... but on disk...
1077 bool bReferencedByLoader = true;
1078 bool bReferencedByHandler = true;
1079 if (bAllLoadersShouldExist)
1080 bReferencedByLoader = !impl_searchFrameLoaderForType(sType).isEmpty();
1082 if (bAllHandlersShouldExist)
1083 bReferencedByHandler = !impl_searchContentHandlerForType(sType).isEmpty();
1085 if (
1086 (!bReferencedByLoader ) &&
1087 (!bReferencedByHandler)
1090 sLog.append("Warning\t:\t" "The type \"" + sType + "\" is not used by any filter, loader or content handler.\n");
1091 ++nWarnings;
1095 if (!sPrefFilter.isEmpty())
1097 CacheItemList::const_iterator pIt2 = m_lFilters.find(sPrefFilter);
1098 if (pIt2 == m_lFilters.end())
1100 if (bAllFiltersShouldExist)
1102 ++nWarnings; // preferred filters can point to a non-installed office module ! no error ... it's a warning only .-(
1103 sLog.append("error\t:\t");
1105 else
1107 ++nWarnings;
1108 sLog.append("warning\t:\t");
1111 sLog.append("The type \"" + sType + "\" points to an invalid filter \"" + sPrefFilter + "\".\n");
1112 continue;
1115 CacheItem aPrefFilter = pIt2->second;
1116 OUString sFilterTypeReg;
1117 aPrefFilter[PROPNAME_TYPE] >>= sFilterTypeReg;
1118 if (sFilterTypeReg != sType)
1120 sLog.append("error\t:\t" "The preferred filter \"" +
1121 sPrefFilter + "\" of type \"" + sType +
1122 "\" is registered for another type \"" + sFilterTypeReg +
1123 "\".\n");
1124 ++nErrors;
1127 sal_Int32 nFlags = 0;
1128 aPrefFilter[PROPNAME_FLAGS] >>= nFlags;
1129 if (!(static_cast<SfxFilterFlags>(nFlags) & SfxFilterFlags::IMPORT))
1131 sLog.append("error\t:\t" "The preferred filter \"" + sPrefFilter + "\" of type \"" +
1132 sType + "\" is not an IMPORT filter!\n");
1133 ++nErrors;
1136 OUString sInternalFilterNameCheck;
1137 aPrefFilter[PROPNAME_NAME] >>= sInternalFilterNameCheck;
1138 if (sInternalFilterNameCheck != sPrefFilter)
1140 sLog.append("Warning\t:\t" "The filter \"" + sPrefFilter +
1141 "\" does support the property \"Name\" correctly.\n");
1142 ++nWarnings;
1145 #endif
1148 // create dependencies between the global default frame loader
1149 // and all types (and of course if registered filters), which
1150 // does not registered for any other loader.
1151 css::uno::Any aDirectValue = impl_getDirectCFGValue(rGuard, CFGDIRECTKEY_DEFAULTFRAMELOADER);
1152 OUString sDefaultFrameLoader;
1154 if (
1155 (!(aDirectValue >>= sDefaultFrameLoader)) ||
1156 (sDefaultFrameLoader.isEmpty() )
1159 sLog.append("error\t:\t" "There is no valid default frame loader!?\n");
1160 ++nErrors;
1163 // a) get list of all well known types
1164 // b) step over all well known frame loader services
1165 // and remove all types from list a), which already
1166 // referenced by a loader b)
1167 std::vector<OUString> lTypes = getItemNames(rGuard, E_TYPE);
1168 for (auto & frameLoader : m_lFrameLoaders)
1170 // Note: of course the default loader must be ignored here.
1171 // Because we replace its registration later completely with all
1172 // types, which are not referenced by any other loader.
1173 // So we can avoid our code against the complexity of a diff!
1174 OUString sLoader = frameLoader.first;
1175 if (sLoader == sDefaultFrameLoader)
1176 continue;
1178 CacheItem& rLoader = frameLoader.second;
1179 css::uno::Any& rTypesReg = rLoader[PROPNAME_TYPES];
1180 const css::uno::Sequence<OUString> lTypesReg = rTypesReg.get<css::uno::Sequence<OUString> >();
1182 for (auto const& typeReg : lTypesReg)
1184 auto pTypeCheck = ::std::find(lTypes.begin(), lTypes.end(), typeReg);
1185 if (pTypeCheck != lTypes.end())
1186 lTypes.erase(pTypeCheck);
1190 CacheItem& rDefaultLoader = m_lFrameLoaders[sDefaultFrameLoader];
1191 rDefaultLoader[PROPNAME_NAME ] <<= sDefaultFrameLoader;
1192 rDefaultLoader[PROPNAME_TYPES] <<= comphelper::containerToSequence(lTypes);
1194 OUString sLogOut = sLog.makeStringAndClear();
1195 OSL_ENSURE(!nErrors, OUStringToOString(sLogOut,RTL_TEXTENCODING_UTF8).getStr());
1196 if (nErrors>0)
1197 throw css::document::CorruptedFilterConfigurationException(
1198 "filter configuration: " + sLogOut,
1199 css::uno::Reference< css::uno::XInterface >(),
1200 sLogOut);
1201 #if OSL_DEBUG_LEVEL > 0
1202 OSL_ENSURE(!nWarnings, OUStringToOString(sLogOut,RTL_TEXTENCODING_UTF8).getStr());
1203 #endif
1206 void FilterCache::impl_addItem2FlushList( EItemType eType,
1207 const OUString& sItem)
1209 std::vector<OUString>* pList = nullptr;
1210 switch(eType)
1212 case E_TYPE :
1213 pList = &m_lChangedTypes;
1214 break;
1216 case E_FILTER :
1217 pList = &m_lChangedFilters;
1218 break;
1220 case E_FRAMELOADER :
1221 pList = &m_lChangedFrameLoaders;
1222 break;
1224 case E_CONTENTHANDLER :
1225 pList = &m_lChangedContentHandlers;
1226 break;
1228 default : throw css::uno::RuntimeException("unsupported item type", nullptr);
1231 auto pItem = ::std::find(pList->cbegin(), pList->cend(), sItem);
1232 if (pItem == pList->cend())
1233 pList->push_back(sItem);
1236 FilterCache::EItemFlushState FilterCache::impl_specifyFlushOperation(const css::uno::Reference< css::container::XNameAccess >& xSet ,
1237 const CacheItemList& rList,
1238 const OUString& sItem)
1240 bool bExistsInConfigLayer = xSet->hasByName(sItem);
1241 bool bExistsInMemory = (rList.find(sItem) != rList.end());
1243 EItemFlushState eState( E_ITEM_UNCHANGED );
1245 // !? ... such situation can occur, if an item was added and(!) removed before it was flushed :-)
1246 if (!bExistsInConfigLayer && !bExistsInMemory)
1247 eState = E_ITEM_UNCHANGED;
1248 else if (!bExistsInConfigLayer && bExistsInMemory)
1249 eState = E_ITEM_ADDED;
1250 else if (bExistsInConfigLayer && bExistsInMemory)
1251 eState = E_ITEM_CHANGED;
1252 else if (bExistsInConfigLayer && !bExistsInMemory)
1253 eState = E_ITEM_REMOVED;
1255 return eState;
1258 void FilterCache::impl_load(std::unique_lock<std::mutex>& rGuard, EFillState eRequiredState)
1260 // Attention: Detect services are part of the standard set!
1261 // So there is no need to handle it separately.
1264 // a) The standard set of config value is needed.
1265 if (
1266 ((eRequiredState & E_CONTAINS_STANDARD) == E_CONTAINS_STANDARD) &&
1267 ((m_eFillState & E_CONTAINS_STANDARD) != E_CONTAINS_STANDARD)
1270 // Attention! If config couldn't be opened successfully
1271 // and exception is thrown automatically and must be forwarded
1272 // to our caller...
1273 css::uno::Reference< css::container::XNameAccess > xTypes(impl_openConfig(rGuard, E_PROVIDER_TYPES), css::uno::UNO_QUERY_THROW);
1275 SAL_INFO( "filter.config", "FilterCache::load std");
1276 impl_loadSet(rGuard, xTypes, E_TYPE, E_READ_STANDARD, &m_lTypes);
1281 // b) We need all type information ...
1282 if (
1283 ((eRequiredState & E_CONTAINS_TYPES) == E_CONTAINS_TYPES) &&
1284 ((m_eFillState & E_CONTAINS_TYPES) != E_CONTAINS_TYPES)
1287 // Attention! If config couldn't be opened successfully
1288 // and exception is thrown automatically and must be forwarded
1289 // to our call...
1290 css::uno::Reference< css::container::XNameAccess > xTypes(impl_openConfig(rGuard, E_PROVIDER_TYPES), css::uno::UNO_QUERY_THROW);
1292 SAL_INFO( "filter.config", "FilterCache::load all types");
1293 impl_loadSet(rGuard, xTypes, E_TYPE, E_READ_UPDATE, &m_lTypes);
1298 // c) We need all filter information ...
1299 if (
1300 ((eRequiredState & E_CONTAINS_FILTERS) == E_CONTAINS_FILTERS) &&
1301 ((m_eFillState & E_CONTAINS_FILTERS) != E_CONTAINS_FILTERS)
1304 // Attention! If config couldn't be opened successfully
1305 // and exception is thrown automatically and must be forwarded
1306 // to our call...
1307 css::uno::Reference< css::container::XNameAccess > xFilters(impl_openConfig(rGuard, E_PROVIDER_FILTERS), css::uno::UNO_QUERY_THROW);
1309 SAL_INFO( "filter.config", "FilterCache::load all filters");
1310 impl_loadSet(rGuard, xFilters, E_FILTER, E_READ_ALL, &m_lFilters);
1315 // c) We need all frame loader information ...
1316 if (
1317 ((eRequiredState & E_CONTAINS_FRAMELOADERS) == E_CONTAINS_FRAMELOADERS) &&
1318 ((m_eFillState & E_CONTAINS_FRAMELOADERS) != E_CONTAINS_FRAMELOADERS)
1321 // Attention! If config couldn't be opened successfully
1322 // and exception is thrown automatically and must be forwarded
1323 // to our call...
1324 css::uno::Reference< css::container::XNameAccess > xLoaders(impl_openConfig(rGuard, E_PROVIDER_OTHERS), css::uno::UNO_QUERY_THROW);
1326 SAL_INFO( "filter.config", "FilterCache::load all frame loader");
1327 impl_loadSet(rGuard, xLoaders, E_FRAMELOADER, E_READ_ALL, &m_lFrameLoaders);
1332 // d) We need all content handler information...
1333 if (
1334 ((eRequiredState & E_CONTAINS_CONTENTHANDLERS) == E_CONTAINS_CONTENTHANDLERS) &&
1335 ((m_eFillState & E_CONTAINS_CONTENTHANDLERS) != E_CONTAINS_CONTENTHANDLERS)
1338 // Attention! If config couldn't be opened successfully
1339 // and exception is thrown automatically and must be forwarded
1340 // to our call...
1341 css::uno::Reference< css::container::XNameAccess > xHandlers(impl_openConfig(rGuard, E_PROVIDER_OTHERS), css::uno::UNO_QUERY_THROW);
1343 SAL_INFO( "filter.config", "FilterCache::load all content handler");
1344 impl_loadSet(rGuard, xHandlers, E_CONTENTHANDLER, E_READ_ALL, &m_lContentHandlers);
1348 // update fill state. Note: it's a bit field, which combines different parts.
1349 m_eFillState = static_cast<EFillState>(static_cast<sal_Int32>(m_eFillState) | static_cast<sal_Int32>(eRequiredState));
1351 // any data read?
1352 // yes! => validate it and update optimized structures.
1353 impl_validateAndOptimize(rGuard);
1356 void FilterCache::impl_loadSet(std::unique_lock<std::mutex>& rGuard,
1357 const css::uno::Reference< css::container::XNameAccess >& xConfig,
1358 EItemType eType ,
1359 EReadOption eOption,
1360 CacheItemList* pCache )
1362 // get access to the right configuration set
1363 OUString sSetName;
1364 switch(eType)
1366 case E_TYPE :
1367 sSetName = CFGSET_TYPES;
1368 break;
1370 case E_FILTER :
1371 sSetName = CFGSET_FILTERS;
1372 break;
1374 case E_FRAMELOADER :
1375 sSetName = CFGSET_FRAMELOADERS;
1376 break;
1378 case E_CONTENTHANDLER :
1379 sSetName = CFGSET_CONTENTHANDLERS;
1380 break;
1381 default: break;
1384 css::uno::Reference< css::container::XNameAccess > xSet;
1385 css::uno::Sequence< OUString > lItems;
1389 css::uno::Any aVal = xConfig->getByName(sSetName);
1390 if (!(aVal >>= xSet) || !xSet.is())
1392 OUString sMsg("Could not open configuration set \"" + sSetName + "\".");
1393 throw css::uno::Exception(sMsg, css::uno::Reference< css::uno::XInterface >());
1395 lItems = xSet->getElementNames();
1397 catch(const css::uno::Exception& ex)
1399 throw css::document::CorruptedFilterConfigurationException(
1400 "filter configuration, caught: " + ex.Message,
1401 css::uno::Reference< css::uno::XInterface >(),
1402 ex.Message);
1405 // get names of all existing sub items of this set
1406 // step over it and fill internal cache structures.
1408 // But don't update optimized structures like e.g. hash
1409 // for mapping extensions to its types!
1411 const OUString* pItems = lItems.getConstArray();
1412 sal_Int32 c = lItems.getLength();
1413 for (sal_Int32 i=0; i<c; ++i)
1415 CacheItemList::iterator pItem = pCache->find(pItems[i]);
1416 switch(eOption)
1418 // a) read a standard set of properties only or read all
1419 case E_READ_STANDARD :
1420 case E_READ_ALL :
1424 (*pCache)[pItems[i]] = impl_loadItem(rGuard, xSet, eType, pItems[i], eOption);
1426 catch(const css::uno::Exception& ex)
1428 throw css::document::CorruptedFilterConfigurationException(
1429 "filter configuration, caught: " + ex.Message,
1430 css::uno::Reference< css::uno::XInterface >(),
1431 ex.Message);
1434 break;
1436 // b) read optional properties only!
1437 // All items must already exist inside our cache.
1438 // But they must be updated.
1439 case E_READ_UPDATE :
1441 if (pItem == pCache->end())
1443 OUString sMsg("item \"" + pItems[i] + "\" not found for update!");
1444 throw css::uno::Exception(sMsg, css::uno::Reference< css::uno::XInterface >());
1448 CacheItem aItem = impl_loadItem(rGuard, xSet, eType, pItems[i], eOption);
1449 pItem->second.update(aItem);
1451 catch(const css::uno::Exception& ex)
1453 throw css::document::CorruptedFilterConfigurationException(
1454 "filter configuration, caught: " + ex.Message,
1455 css::uno::Reference< css::uno::XInterface >(),
1456 ex.Message);
1459 break;
1460 default: break;
1465 void FilterCache::impl_readPatchUINames(std::unique_lock<std::mutex>& /*rGuard*/,
1466 const css::uno::Reference< css::container::XNameAccess >& xNode,
1467 CacheItem& rItem)
1470 OUString sActLocale = m_sActLocale ;
1472 css::uno::Any aVal = xNode->getByName(PROPNAME_UINAME);
1473 css::uno::Reference< css::container::XNameAccess > xUIName;
1474 if (!(aVal >>= xUIName) && !xUIName.is())
1475 return;
1477 const ::std::vector< OUString > lLocales(comphelper::sequenceToContainer< ::std::vector< OUString >>(
1478 xUIName->getElementNames()));
1479 ::std::vector< OUString >::const_iterator pLocale ;
1480 ::comphelper::SequenceAsHashMap lUINames;
1482 for (auto const& locale : lLocales)
1484 OUString sValue;
1485 xUIName->getByName(locale) >>= sValue;
1487 lUINames[locale] <<= sValue;
1490 aVal <<= lUINames.getAsConstPropertyValueList();
1491 rItem[PROPNAME_UINAMES] = aVal;
1493 // find right UIName for current office locale
1494 // Use fallbacks too!
1495 pLocale = LanguageTag::getFallback(lLocales, sActLocale);
1496 if (pLocale == lLocales.end())
1498 #if OSL_DEBUG_LEVEL > 0
1499 if ( sActLocale == "en-US" )
1500 return;
1501 OUString sName = rItem.getUnpackedValueOrDefault(PROPNAME_NAME, OUString());
1503 SAL_WARN("filter.config", "Fallback scenario for filter or type '" << sName << "' and locale '" <<
1504 sActLocale << "' failed. Please check your filter configuration.");
1505 #endif
1506 return;
1509 const OUString& sLocale = *pLocale;
1510 ::comphelper::SequenceAsHashMap::const_iterator pUIName = lUINames.find(sLocale);
1511 if (pUIName != lUINames.end())
1512 rItem[PROPNAME_UINAME] = pUIName->second;
1515 void FilterCache::impl_savePatchUINames(const css::uno::Reference< css::container::XNameReplace >& xNode,
1516 const CacheItem& rItem)
1518 css::uno::Reference< css::container::XNameContainer > xAdd (xNode, css::uno::UNO_QUERY);
1520 css::uno::Sequence< css::beans::PropertyValue > lUINames = rItem.getUnpackedValueOrDefault(PROPNAME_UINAMES, css::uno::Sequence< css::beans::PropertyValue >());
1521 sal_Int32 c = lUINames.getLength();
1522 const css::beans::PropertyValue* pUINames = lUINames.getConstArray();
1524 for (sal_Int32 i=0; i<c; ++i)
1526 if (xNode->hasByName(pUINames[i].Name))
1527 xNode->replaceByName(pUINames[i].Name, pUINames[i].Value);
1528 else
1529 xAdd->insertByName(pUINames[i].Name, pUINames[i].Value);
1533 /*-----------------------------------------------
1534 TODO
1535 clarify, how the real problem behind the
1536 wrong constructed CacheItem instance (which
1537 will force a crash during destruction)
1538 can be solved ...
1539 -----------------------------------------------*/
1540 CacheItem FilterCache::impl_loadItem(std::unique_lock<std::mutex>& rGuard,
1541 const css::uno::Reference< css::container::XNameAccess >& xSet ,
1542 EItemType eType ,
1543 const OUString& sItem ,
1544 EReadOption eOption)
1546 // try to get an API object, which points directly to the
1547 // requested item. If it fail an exception should occur and
1548 // break this operation. Of course returned API object must be
1549 // checked too.
1550 css::uno::Reference< css::container::XNameAccess > xItem;
1551 css::uno::Any aVal = xSet->getByName(sItem);
1552 if (!(aVal >>= xItem) || !xItem.is())
1554 throw css::uno::RuntimeException("found corrupted item \"" + sItem + "\".",
1555 css::uno::Reference< css::uno::XInterface >());
1558 // set too. Of course it's already used as key into the e.g. outside
1559 // used hash map... but some of our API methods provide
1560 // this property set as result only. But the user of this CacheItem
1561 // should know, which value the key names has :-) IT'S IMPORTANT!
1562 CacheItem aItem;
1563 aItem[PROPNAME_NAME] <<= sItem;
1564 switch(eType)
1566 case E_TYPE :
1568 assert(eOption >= 0 && eOption <= E_READ_ALL);
1569 css::uno::Sequence< OUString > &rNames = m_aTypeProps[eOption];
1571 // read standard properties of a filter
1572 if (rNames.hasElements())
1574 css::uno::Reference< css::beans::XMultiPropertySet >
1575 xPropSet( xItem, css::uno::UNO_QUERY_THROW);
1576 css::uno::Sequence< css::uno::Any > aValues = xPropSet->getPropertyValues(rNames);
1578 for (sal_Int32 i = 0; i < aValues.getLength(); i++)
1579 aItem[rNames[i]] = aValues[i];
1582 // read optional properties of a type
1583 // no else here! Is an additional switch ...
1584 if (eOption == E_READ_UPDATE || eOption == E_READ_ALL)
1585 impl_readPatchUINames(rGuard, xItem, aItem);
1587 break;
1590 case E_FILTER :
1592 assert(eOption >= 0 && eOption <= E_READ_ALL);
1593 css::uno::Sequence< OUString > &rNames = m_aStandardProps[eOption];
1595 // read standard properties of a filter
1596 if (rNames.hasElements())
1598 css::uno::Reference< css::beans::XMultiPropertySet >
1599 xPropSet( xItem, css::uno::UNO_QUERY_THROW);
1600 css::uno::Sequence< css::uno::Any > aValues = xPropSet->getPropertyValues(rNames);
1602 for (sal_Int32 i = 0; i < rNames.getLength(); i++)
1604 const OUString &rPropName = rNames[i];
1605 if (i != rNames.getLength() - 1 || rPropName != PROPNAME_FLAGS)
1606 aItem[rPropName] = aValues[i];
1607 else
1609 assert(rPropName == PROPNAME_FLAGS);
1610 // special handling for flags! Convert it from a list of names to its
1611 // int representation ...
1612 css::uno::Sequence< OUString > lFlagNames;
1613 if (aValues[i] >>= lFlagNames)
1614 aItem[rPropName] <<= static_cast<sal_Int32>(FilterCache::impl_convertFlagNames2FlagField(lFlagNames));
1618 //TODO remove it if moving of filter uinames to type uinames
1619 // will be finished really
1620 #ifdef AS_ENABLE_FILTER_UINAMES
1621 if (eOption == E_READ_UPDATE || eOption == E_READ_ALL)
1622 impl_readPatchUINames(rGuard, xItem, aItem);
1623 #endif // AS_ENABLE_FILTER_UINAMES
1625 break;
1627 case E_FRAMELOADER :
1628 case E_CONTENTHANDLER :
1629 aItem[PROPNAME_TYPES] = xItem->getByName(PROPNAME_TYPES);
1630 break;
1631 default: break;
1634 return aItem;
1637 CacheItemList::iterator FilterCache::impl_loadItemOnDemand( std::unique_lock<std::mutex>& rGuard,
1638 EItemType eType,
1639 const OUString& sItem)
1641 CacheItemList* pList = nullptr;
1642 css::uno::Reference< css::uno::XInterface > xConfig ;
1643 OUString sSet ;
1645 switch(eType)
1647 case E_TYPE :
1649 pList = &m_lTypes;
1650 xConfig = impl_openConfig(rGuard, E_PROVIDER_TYPES);
1651 sSet = CFGSET_TYPES;
1653 break;
1655 case E_FILTER :
1657 pList = &m_lFilters;
1658 xConfig = impl_openConfig(rGuard, E_PROVIDER_FILTERS);
1659 sSet = CFGSET_FILTERS;
1661 break;
1663 case E_FRAMELOADER :
1665 pList = &m_lFrameLoaders;
1666 xConfig = impl_openConfig(rGuard, E_PROVIDER_OTHERS);
1667 sSet = CFGSET_FRAMELOADERS;
1669 break;
1671 case E_CONTENTHANDLER :
1673 pList = &m_lContentHandlers;
1674 xConfig = impl_openConfig(rGuard, E_PROVIDER_OTHERS);
1675 sSet = CFGSET_CONTENTHANDLERS;
1677 break;
1680 if (!pList)
1681 throw css::container::NoSuchElementException();
1683 css::uno::Reference< css::container::XNameAccess > xRoot(xConfig, css::uno::UNO_QUERY_THROW);
1684 css::uno::Reference< css::container::XNameAccess > xSet ;
1685 xRoot->getByName(sSet) >>= xSet;
1687 CacheItemList::iterator pItemInCache = pList->find(sItem);
1688 bool bItemInConfig = xSet->hasByName(sItem);
1690 if (bItemInConfig)
1692 (*pList)[sItem] = impl_loadItem(rGuard, xSet, eType, sItem, E_READ_ALL);
1694 else
1696 if (pItemInCache != pList->end())
1697 pList->erase(pItemInCache);
1698 // OK - this item does not exists inside configuration.
1699 // And we already updated our internal cache.
1700 // But the outside code needs this NoSuchElementException
1701 // to know, that this item does notexists.
1702 // Nobody checks the iterator!
1703 throw css::container::NoSuchElementException();
1706 return pList->find(sItem);
1709 void FilterCache::impl_saveItem(const css::uno::Reference< css::container::XNameReplace >& xItem,
1710 EItemType eType,
1711 const CacheItem & aItem)
1713 // This function changes the properties of aItem one-by-one; but it also
1714 // listens to the configuration changes and reloads the whole item from the
1715 // configuration on change, so use a copy of aItem throughout:
1716 CacheItem copiedItem(aItem);
1718 CacheItem::const_iterator pIt;
1719 switch(eType)
1722 case E_TYPE :
1724 pIt = copiedItem.find(PROPNAME_PREFERREDFILTER);
1725 if (pIt != copiedItem.end())
1726 xItem->replaceByName(PROPNAME_PREFERREDFILTER, pIt->second);
1727 pIt = copiedItem.find(PROPNAME_DETECTSERVICE);
1728 if (pIt != copiedItem.end())
1729 xItem->replaceByName(PROPNAME_DETECTSERVICE, pIt->second);
1730 pIt = copiedItem.find(PROPNAME_URLPATTERN);
1731 if (pIt != copiedItem.end())
1732 xItem->replaceByName(PROPNAME_URLPATTERN, pIt->second);
1733 pIt = copiedItem.find(PROPNAME_EXTENSIONS);
1734 if (pIt != copiedItem.end())
1735 xItem->replaceByName(PROPNAME_EXTENSIONS, pIt->second);
1736 pIt = copiedItem.find(PROPNAME_PREFERRED);
1737 if (pIt != copiedItem.end())
1738 xItem->replaceByName(PROPNAME_PREFERRED, pIt->second);
1739 pIt = copiedItem.find(PROPNAME_MEDIATYPE);
1740 if (pIt != copiedItem.end())
1741 xItem->replaceByName(PROPNAME_MEDIATYPE, pIt->second);
1742 pIt = copiedItem.find(PROPNAME_CLIPBOARDFORMAT);
1743 if (pIt != copiedItem.end())
1744 xItem->replaceByName(PROPNAME_CLIPBOARDFORMAT, pIt->second);
1746 css::uno::Reference< css::container::XNameReplace > xUIName;
1747 xItem->getByName(PROPNAME_UINAME) >>= xUIName;
1748 impl_savePatchUINames(xUIName, copiedItem);
1750 break;
1753 case E_FILTER :
1755 pIt = copiedItem.find(PROPNAME_TYPE);
1756 if (pIt != copiedItem.end())
1757 xItem->replaceByName(PROPNAME_TYPE, pIt->second);
1758 pIt = copiedItem.find(PROPNAME_FILEFORMATVERSION);
1759 if (pIt != copiedItem.end())
1760 xItem->replaceByName(PROPNAME_FILEFORMATVERSION, pIt->second);
1761 pIt = copiedItem.find(PROPNAME_UICOMPONENT);
1762 if (pIt != copiedItem.end())
1763 xItem->replaceByName(PROPNAME_UICOMPONENT, pIt->second);
1764 pIt = copiedItem.find(PROPNAME_FILTERSERVICE);
1765 if (pIt != copiedItem.end())
1766 xItem->replaceByName(PROPNAME_FILTERSERVICE, pIt->second);
1767 pIt = copiedItem.find(PROPNAME_DOCUMENTSERVICE);
1768 if (pIt != copiedItem.end())
1769 xItem->replaceByName(PROPNAME_DOCUMENTSERVICE, pIt->second);
1770 pIt = copiedItem.find(PROPNAME_USERDATA);
1771 if (pIt != copiedItem.end())
1772 xItem->replaceByName(PROPNAME_USERDATA, pIt->second);
1773 pIt = copiedItem.find(PROPNAME_TEMPLATENAME);
1774 if (pIt != copiedItem.end())
1775 xItem->replaceByName(PROPNAME_TEMPLATENAME, pIt->second);
1777 // special handling for flags! Convert it from an integer flag field back
1778 // to a list of names ...
1779 pIt = copiedItem.find(PROPNAME_FLAGS);
1780 if (pIt != copiedItem.end())
1782 sal_Int32 nFlags = 0;
1783 pIt->second >>= nFlags;
1784 css::uno::Any aFlagNameList;
1785 aFlagNameList <<= FilterCache::impl_convertFlagField2FlagNames(static_cast<SfxFilterFlags>(nFlags));
1786 xItem->replaceByName(PROPNAME_FLAGS, aFlagNameList);
1789 //TODO remove it if moving of filter uinames to type uinames
1790 // will be finished really
1791 #ifdef AS_ENABLE_FILTER_UINAMES
1792 css::uno::Reference< css::container::XNameReplace > xUIName;
1793 xItem->getByName(PROPNAME_UINAME) >>= xUIName;
1794 impl_savePatchUINames(xUIName, copiedItem);
1795 #endif // AS_ENABLE_FILTER_UINAMES
1797 break;
1800 case E_FRAMELOADER :
1801 case E_CONTENTHANDLER :
1803 pIt = copiedItem.find(PROPNAME_TYPES);
1804 if (pIt != copiedItem.end())
1805 xItem->replaceByName(PROPNAME_TYPES, pIt->second);
1807 break;
1808 default: break;
1812 /*-----------------------------------------------
1813 static! => no locks necessary
1814 -----------------------------------------------*/
1815 css::uno::Sequence< OUString > FilterCache::impl_convertFlagField2FlagNames(SfxFilterFlags nFlags)
1817 std::vector<OUString> lFlagNames;
1819 if (nFlags & SfxFilterFlags::STARONEFILTER ) lFlagNames.emplace_back(FLAGNAME_3RDPARTYFILTER );
1820 if (nFlags & SfxFilterFlags::ALIEN ) lFlagNames.emplace_back(FLAGNAME_ALIEN );
1821 if (nFlags & SfxFilterFlags::CONSULTSERVICE ) lFlagNames.emplace_back(FLAGNAME_CONSULTSERVICE );
1822 if (nFlags & SfxFilterFlags::DEFAULT ) lFlagNames.emplace_back(FLAGNAME_DEFAULT );
1823 if (nFlags & SfxFilterFlags::ENCRYPTION ) lFlagNames.emplace_back(FLAGNAME_ENCRYPTION );
1824 if (nFlags & SfxFilterFlags::EXPORT ) lFlagNames.emplace_back(FLAGNAME_EXPORT );
1825 if (nFlags & SfxFilterFlags::IMPORT ) lFlagNames.emplace_back(FLAGNAME_IMPORT );
1826 if (nFlags & SfxFilterFlags::INTERNAL ) lFlagNames.emplace_back(FLAGNAME_INTERNAL );
1827 if (nFlags & SfxFilterFlags::NOTINFILEDLG ) lFlagNames.emplace_back(FLAGNAME_NOTINFILEDIALOG );
1828 if (nFlags & SfxFilterFlags::MUSTINSTALL ) lFlagNames.emplace_back(FLAGNAME_NOTINSTALLED );
1829 if (nFlags & SfxFilterFlags::OWN ) lFlagNames.emplace_back(FLAGNAME_OWN );
1830 if (nFlags & SfxFilterFlags::PACKED ) lFlagNames.emplace_back(FLAGNAME_PACKED );
1831 if (nFlags & SfxFilterFlags::PASSWORDTOMODIFY ) lFlagNames.emplace_back(FLAGNAME_PASSWORDTOMODIFY );
1832 if (nFlags & SfxFilterFlags::PREFERED ) lFlagNames.emplace_back(FLAGNAME_PREFERRED );
1833 if (nFlags & SfxFilterFlags::STARTPRESENTATION) lFlagNames.emplace_back(FLAGNAME_STARTPRESENTATION);
1834 if (nFlags & SfxFilterFlags::OPENREADONLY ) lFlagNames.emplace_back(FLAGNAME_READONLY );
1835 if (nFlags & SfxFilterFlags::SUPPORTSSELECTION) lFlagNames.emplace_back(FLAGNAME_SUPPORTSSELECTION);
1836 if (nFlags & SfxFilterFlags::TEMPLATE ) lFlagNames.emplace_back(FLAGNAME_TEMPLATE );
1837 if (nFlags & SfxFilterFlags::TEMPLATEPATH ) lFlagNames.emplace_back(FLAGNAME_TEMPLATEPATH );
1838 if (nFlags & SfxFilterFlags::COMBINED ) lFlagNames.emplace_back(FLAGNAME_COMBINED );
1839 if (nFlags & SfxFilterFlags::SUPPORTSSIGNING) lFlagNames.emplace_back(FLAGNAME_SUPPORTSSIGNING);
1840 if (nFlags & SfxFilterFlags::GPGENCRYPTION) lFlagNames.emplace_back(FLAGNAME_GPGENCRYPTION);
1841 if (nFlags & SfxFilterFlags::EXOTIC) lFlagNames.emplace_back(FLAGNAME_EXOTIC);
1843 return comphelper::containerToSequence(lFlagNames);
1846 /*-----------------------------------------------
1847 static! => no locks necessary
1848 -----------------------------------------------*/
1849 SfxFilterFlags FilterCache::impl_convertFlagNames2FlagField(const css::uno::Sequence< OUString >& lNames)
1851 SfxFilterFlags nField = SfxFilterFlags::NONE;
1853 const OUString* pNames = lNames.getConstArray();
1854 sal_Int32 c = lNames.getLength();
1855 for (sal_Int32 i=0; i<c; ++i)
1857 if (pNames[i] == FLAGNAME_3RDPARTYFILTER)
1859 nField |= SfxFilterFlags::STARONEFILTER;
1860 continue;
1862 if (pNames[i] == FLAGNAME_ALIEN)
1864 nField |= SfxFilterFlags::ALIEN;
1865 continue;
1867 if (pNames[i] == FLAGNAME_CONSULTSERVICE)
1869 nField |= SfxFilterFlags::CONSULTSERVICE;
1870 continue;
1872 if (pNames[i] == FLAGNAME_DEFAULT)
1874 nField |= SfxFilterFlags::DEFAULT;
1875 continue;
1877 if (pNames[i] == FLAGNAME_ENCRYPTION)
1879 nField |= SfxFilterFlags::ENCRYPTION;
1880 continue;
1882 if (pNames[i] == FLAGNAME_EXOTIC)
1884 nField |= SfxFilterFlags::EXOTIC;
1885 continue;
1887 if (pNames[i] == FLAGNAME_EXPORT)
1889 nField |= SfxFilterFlags::EXPORT;
1890 continue;
1892 if (pNames[i] == FLAGNAME_GPGENCRYPTION)
1894 nField |= SfxFilterFlags::GPGENCRYPTION;
1895 continue;
1897 if (pNames[i] == FLAGNAME_IMPORT)
1899 nField |= SfxFilterFlags::IMPORT;
1900 continue;
1902 if (pNames[i] == FLAGNAME_INTERNAL)
1904 nField |= SfxFilterFlags::INTERNAL;
1905 continue;
1907 if (pNames[i] == FLAGNAME_NOTINFILEDIALOG)
1909 nField |= SfxFilterFlags::NOTINFILEDLG;
1910 continue;
1912 if (pNames[i] == FLAGNAME_NOTINSTALLED)
1914 nField |= SfxFilterFlags::MUSTINSTALL;
1915 continue;
1917 if (pNames[i] == FLAGNAME_OWN)
1919 nField |= SfxFilterFlags::OWN;
1920 continue;
1922 if (pNames[i] == FLAGNAME_PACKED)
1924 nField |= SfxFilterFlags::PACKED;
1925 continue;
1927 if (pNames[i] == FLAGNAME_PASSWORDTOMODIFY)
1929 nField |= SfxFilterFlags::PASSWORDTOMODIFY;
1930 continue;
1932 if (pNames[i] == FLAGNAME_PREFERRED)
1934 nField |= SfxFilterFlags::PREFERED;
1935 continue;
1937 if (pNames[i] == FLAGNAME_STARTPRESENTATION)
1939 nField |= SfxFilterFlags::STARTPRESENTATION;
1940 continue;
1942 if (pNames[i] == FLAGNAME_SUPPORTSSIGNING)
1944 nField |= SfxFilterFlags::SUPPORTSSIGNING;
1945 continue;
1947 if (pNames[i] == FLAGNAME_READONLY)
1949 nField |= SfxFilterFlags::OPENREADONLY;
1950 continue;
1952 if (pNames[i] == FLAGNAME_SUPPORTSSELECTION)
1954 nField |= SfxFilterFlags::SUPPORTSSELECTION;
1955 continue;
1957 if (pNames[i] == FLAGNAME_TEMPLATE)
1959 nField |= SfxFilterFlags::TEMPLATE;
1960 continue;
1962 if (pNames[i] == FLAGNAME_TEMPLATEPATH)
1964 nField |= SfxFilterFlags::TEMPLATEPATH;
1965 continue;
1967 if (pNames[i] == FLAGNAME_COMBINED)
1969 nField |= SfxFilterFlags::COMBINED;
1970 continue;
1974 return nField;
1978 void FilterCache::impl_interpretDataVal4Type(const OUString& sValue,
1979 sal_Int32 nProp ,
1980 CacheItem& rItem )
1982 switch(nProp)
1984 // Preferred
1985 case 0: rItem[PROPNAME_PREFERRED] <<= (sValue.toInt32() == 1);
1986 break;
1987 // MediaType
1988 case 1: rItem[PROPNAME_MEDIATYPE] <<= ::rtl::Uri::decode(sValue, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8);
1989 break;
1990 // ClipboardFormat
1991 case 2: rItem[PROPNAME_CLIPBOARDFORMAT] <<= ::rtl::Uri::decode(sValue, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8);
1992 break;
1993 // URLPattern
1994 case 3: rItem[PROPNAME_URLPATTERN] <<= comphelper::containerToSequence(impl_tokenizeString(sValue, ';'));
1995 break;
1996 // Extensions
1997 case 4: rItem[PROPNAME_EXTENSIONS] <<= comphelper::containerToSequence(impl_tokenizeString(sValue, ';'));
1998 break;
2003 void FilterCache::impl_interpretDataVal4Filter(const OUString& sValue,
2004 sal_Int32 nProp ,
2005 CacheItem& rItem )
2007 switch(nProp)
2009 // Order
2010 case 0: {
2011 sal_Int32 nOrder = sValue.toInt32();
2012 if (nOrder > 0)
2014 SAL_WARN( "filter.config", "FilterCache::impl_interpretDataVal4Filter()\nCan not move Order value from filter to type on demand!");
2017 break;
2018 // Type
2019 case 1: rItem[PROPNAME_TYPE] <<= ::rtl::Uri::decode(sValue, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8);
2020 break;
2021 // DocumentService
2022 case 2: rItem[PROPNAME_DOCUMENTSERVICE] <<= ::rtl::Uri::decode(sValue, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8);
2023 break;
2024 // FilterService
2025 case 3: rItem[PROPNAME_FILTERSERVICE] <<= ::rtl::Uri::decode(sValue, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8);
2026 break;
2027 // Flags
2028 case 4: rItem[PROPNAME_FLAGS] <<= sValue.toInt32();
2029 break;
2030 // UserData
2031 case 5: rItem[PROPNAME_USERDATA] <<= comphelper::containerToSequence(impl_tokenizeString(sValue, ';'));
2032 break;
2033 // FileFormatVersion
2034 case 6: rItem[PROPNAME_FILEFORMATVERSION] <<= sValue.toInt32();
2035 break;
2036 // TemplateName
2037 case 7: rItem[PROPNAME_TEMPLATENAME] <<= ::rtl::Uri::decode(sValue, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8);
2038 break;
2039 // [optional!] UIComponent
2040 case 8: rItem[PROPNAME_UICOMPONENT] <<= ::rtl::Uri::decode(sValue, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8);
2041 break;
2045 /*-----------------------------------------------
2046 TODO work on a cache copy first, which can be flushed afterwards
2047 That would be useful to guarantee a consistent cache.
2048 -----------------------------------------------*/
2049 void FilterCache::impl_readOldFormat(std::unique_lock<std::mutex>& rGuard)
2051 // Attention: Opening/Reading of this old configuration format has to be handled gracefully.
2052 // It's optional and should not disturb our normal work!
2053 // E.g. we must check, if the package exists...
2056 css::uno::Reference< css::uno::XInterface > xInt = impl_openConfig(rGuard, E_PROVIDER_OLD);
2057 css::uno::Reference< css::container::XNameAccess > xCfg(xInt, css::uno::UNO_QUERY_THROW);
2059 OUString TYPES_SET("Types");
2061 // May be there is no type set ...
2062 if (xCfg->hasByName(TYPES_SET))
2064 css::uno::Reference< css::container::XNameAccess > xSet;
2065 xCfg->getByName(TYPES_SET) >>= xSet;
2066 const css::uno::Sequence< OUString > lItems = xSet->getElementNames();
2067 for (const OUString& rName : lItems)
2068 m_lTypes[rName] = impl_readOldItem(rGuard, xSet, E_TYPE, rName);
2071 OUString FILTER_SET("Filters");
2072 // May be there is no filter set ...
2073 if (xCfg->hasByName(FILTER_SET))
2075 css::uno::Reference< css::container::XNameAccess > xSet;
2076 xCfg->getByName(FILTER_SET) >>= xSet;
2077 const css::uno::Sequence< OUString > lItems = xSet->getElementNames();
2078 for (const OUString& rName : lItems)
2079 m_lFilters[rName] = impl_readOldItem(rGuard, xSet, E_FILTER, rName);
2082 /* corrupt filter addon? Because it's external (optional) code... we can ignore it. Addon won't work then...
2083 but that seems to be acceptable.
2084 see #139088# for further information
2086 catch(const css::uno::Exception&)
2091 CacheItem FilterCache::impl_readOldItem(std::unique_lock<std::mutex>& rGuard,
2092 const css::uno::Reference< css::container::XNameAccess >& xSet ,
2093 EItemType eType,
2094 const OUString& sItem)
2096 css::uno::Reference< css::container::XNameAccess > xItem;
2097 xSet->getByName(sItem) >>= xItem;
2098 if (!xItem.is())
2099 throw css::uno::Exception("Can not read old item.", css::uno::Reference< css::uno::XInterface >());
2101 CacheItem aItem;
2102 aItem[PROPNAME_NAME] <<= sItem;
2104 // Installed flag ...
2105 // Isn't used any longer!
2107 // UIName
2108 impl_readPatchUINames(rGuard, xItem, aItem);
2110 // Data
2111 OUString sData;
2112 std::vector<OUString> lData;
2113 xItem->getByName( "Data" ) >>= sData;
2114 lData = impl_tokenizeString(sData, ',');
2115 if (
2116 (sData.isEmpty()) ||
2117 (lData.empty() )
2120 throw css::uno::Exception( "Can not read old item property DATA.", css::uno::Reference< css::uno::XInterface >());
2123 sal_Int32 nProp = 0;
2124 for (auto const& prop : lData)
2126 switch(eType)
2128 case E_TYPE :
2129 impl_interpretDataVal4Type(prop, nProp, aItem);
2130 break;
2132 case E_FILTER :
2133 impl_interpretDataVal4Filter(prop, nProp, aItem);
2134 break;
2135 default: break;
2137 ++nProp;
2140 return aItem;
2144 std::vector<OUString> FilterCache::impl_tokenizeString(std::u16string_view sData ,
2145 sal_Unicode cSeparator)
2147 std::vector<OUString> lData ;
2148 sal_Int32 nToken = 0;
2151 OUString sToken( o3tl::getToken(sData, 0, cSeparator, nToken) );
2152 lData.push_back(sToken);
2154 while(nToken >= 0);
2155 return lData;
2158 #if OSL_DEBUG_LEVEL > 0
2161 OUString FilterCache::impl_searchFrameLoaderForType(const OUString& sType) const
2163 for (auto const& frameLoader : m_lFrameLoaders)
2165 const OUString& sItem = frameLoader.first;
2166 ::comphelper::SequenceAsHashMap lProps(frameLoader.second);
2167 const css::uno::Sequence<OUString> lTypes =
2168 lProps[PROPNAME_TYPES].get<css::uno::Sequence<OUString> >();
2170 if (::std::find(lTypes.begin(), lTypes.end(), sType) != lTypes.end())
2171 return sItem;
2174 return OUString();
2178 OUString FilterCache::impl_searchContentHandlerForType(const OUString& sType) const
2180 for (auto const& contentHandler : m_lContentHandlers)
2182 const OUString& sItem = contentHandler.first;
2183 ::comphelper::SequenceAsHashMap lProps(contentHandler.second);
2184 const css::uno::Sequence<OUString> lTypes =
2185 lProps[PROPNAME_TYPES].get<css::uno::Sequence<OUString> >();
2186 if (::std::find(lTypes.begin(), lTypes.end(), sType) != lTypes.end())
2187 return sItem;
2190 return OUString();
2192 #endif
2195 bool FilterCache::impl_isModuleInstalled(std::unique_lock<std::mutex>& /*rGuard*/, const OUString& sModule)
2197 css::uno::Reference< css::container::XNameAccess > xCfg;
2199 if (!m_xModuleCfg.is())
2201 m_xModuleCfg = officecfg::Setup::Office::Factories::get();
2204 xCfg = m_xModuleCfg;
2206 if (xCfg.is())
2207 return xCfg->hasByName(sModule);
2209 return false;
2212 } // namespace filter
2214 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */