1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include <memory>
22 #include <tools/diagnose_ex.h>
23 #include "filtercache.hxx"
24 #include "constant.hxx"
25 #include "cacheupdatelistener.hxx"
26 
27 /*TODO see using below ... */
28 #define AS_ENABLE_FILTER_UINAMES
29 
30 #include <com/sun/star/configuration/theDefaultProvider.hpp>
31 #include <com/sun/star/util/XChangesBatch.hpp>
32 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
33 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
34 #include <com/sun/star/beans/NamedValue.hpp>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/beans/XPropertyAccess.hpp>
37 #include <com/sun/star/beans/XMultiPropertySet.hpp>
38 #include <com/sun/star/beans/XProperty.hpp>
39 #include <com/sun/star/beans/PropertyValue.hpp>
40 #include <com/sun/star/beans/Property.hpp>
41 #include <com/sun/star/beans/PropertyAttribute.hpp>
42 #include <com/sun/star/document/CorruptedFilterConfigurationException.hpp>
43 #include <comphelper/sequence.hxx>
44 #include <comphelper/processfactory.hxx>
45 
46 #include <unotools/configmgr.hxx>
47 #include <unotools/configpaths.hxx>
48 #include <rtl/ustrbuf.hxx>
49 #include <rtl/uri.hxx>
50 #include <sal/log.hxx>
51 #include <tools/urlobj.hxx>
52 #include <tools/wldcrd.hxx>
53 #include <i18nlangtag/languagetag.hxx>
54 
55 #include <officecfg/Setup.hxx>
56 
57 
58 namespace filter{
59     namespace config{
60 
61 FilterCache::FilterCache()
62     : BaseLock    (                                        )
63     , m_eFillState(E_CONTAINS_NOTHING                      )
64 {
65     int i = 0;
66     OUString sStandardProps[10];
67 
68     sStandardProps[i++] = PROPNAME_USERDATA;
69     sStandardProps[i++] = PROPNAME_TEMPLATENAME;
70     sStandardProps[i++] = PROPNAME_ENABLED;
71     // E_READ_UPDATE only above
72     sStandardProps[i++] = PROPNAME_TYPE;
73     sStandardProps[i++] = PROPNAME_FILEFORMATVERSION;
74     sStandardProps[i++] = PROPNAME_UICOMPONENT;
75     sStandardProps[i++] = PROPNAME_FILTERSERVICE;
76     sStandardProps[i++] = PROPNAME_DOCUMENTSERVICE;
77     sStandardProps[i++] = PROPNAME_EXPORTEXTENSION;
78     sStandardProps[i++] = PROPNAME_FLAGS; // must be last.
79     assert(i == SAL_N_ELEMENTS(sStandardProps));
80 
81     // E_READ_NOTHING -> creative nothingness.
82     m_aStandardProps[E_READ_STANDARD] =
83         css::uno::Sequence< OUString >(sStandardProps + 3, 7);
84     m_aStandardProps[E_READ_UPDATE] =
85         css::uno::Sequence< OUString >(sStandardProps, 3);
86     m_aStandardProps[E_READ_ALL] =
87         css::uno::Sequence< OUString >(sStandardProps,
88                                        SAL_N_ELEMENTS(sStandardProps));
89 
90     i = 0;
91     OUString sTypeProps[7];
92     sTypeProps[i++] = PROPNAME_MEDIATYPE;
93     // E_READ_UPDATE only above
94     sTypeProps[i++] = PROPNAME_PREFERREDFILTER;
95     sTypeProps[i++] = PROPNAME_DETECTSERVICE;
96     sTypeProps[i++] = PROPNAME_URLPATTERN;
97     sTypeProps[i++] = PROPNAME_EXTENSIONS;
98     sTypeProps[i++] = PROPNAME_PREFERRED;
99     sTypeProps[i++] = PROPNAME_CLIPBOARDFORMAT;
100     assert(i == SAL_N_ELEMENTS(sTypeProps));
101 
102     // E_READ_NOTHING -> more creative nothingness.
103     m_aTypeProps[E_READ_STANDARD] =
104         css::uno::Sequence< OUString >(sTypeProps + 1, 6);
105     m_aTypeProps[E_READ_UPDATE] =
106         css::uno::Sequence< OUString >(sTypeProps, 1);
107     m_aTypeProps[E_READ_ALL] =
108         css::uno::Sequence< OUString >(sTypeProps,
109                                        SAL_N_ELEMENTS(sTypeProps));
110 }
111 
112 
113 FilterCache::~FilterCache()
114 {
115     if (m_xTypesChglisteners.is())
116         m_xTypesChglisteners->stopListening();
117     if (m_xFiltersChgListener.is())
118         m_xFiltersChgListener->stopListening();
119 }
120 
121 
122 std::unique_ptr<FilterCache> FilterCache::clone() const
123 {
124     // SAFE -> ----------------------------------
125     osl::MutexGuard aLock(m_aLock);
126 
127     auto pClone = std::make_unique<FilterCache>();
128 
129     // Don't copy the configuration access points here.
130     // They will be created on demand inside the cloned instance,
131     // if they are needed.
132 
133     pClone->m_lTypes                     = m_lTypes;
134     pClone->m_lFilters                   = m_lFilters;
135     pClone->m_lFrameLoaders              = m_lFrameLoaders;
136     pClone->m_lContentHandlers           = m_lContentHandlers;
137     pClone->m_lExtensions2Types          = m_lExtensions2Types;
138     pClone->m_lURLPattern2Types          = m_lURLPattern2Types;
139 
140     pClone->m_sActLocale                 = m_sActLocale;
141 
142     pClone->m_eFillState                 = m_eFillState;
143 
144     pClone->m_lChangedTypes              = m_lChangedTypes;
145     pClone->m_lChangedFilters            = m_lChangedFilters;
146     pClone->m_lChangedFrameLoaders       = m_lChangedFrameLoaders;
147     pClone->m_lChangedContentHandlers    = m_lChangedContentHandlers;
148 
149     return pClone;
150     // <- SAFE ----------------------------------
151 }
152 
153 
154 void FilterCache::takeOver(const FilterCache& rClone)
155 {
156     // SAFE -> ----------------------------------
157     osl::MutexGuard aLock(m_aLock);
158 
159     // a)
160     // Don't copy the configuration access points here!
161     // We must use our own ones...
162 
163     // b)
164     // Further we can ignore the uno service manager.
165     // We should already have a valid instance.
166 
167     // c)
168     // Take over only changed items!
169     // Otherwise we risk the following scenario:
170     // c1) clone_1 contains changed filters
171     // c2) clone_2 container changed types
172     // c3) clone_1 take over changed filters and unchanged types
173     // c4) clone_2 take over unchanged filters(!) and changed types(!)
174     // c5) c4 overwrites c3!
175 
176     if (!rClone.m_lChangedTypes.empty())
177         m_lTypes = rClone.m_lTypes;
178     if (!rClone.m_lChangedFilters.empty())
179         m_lFilters = rClone.m_lFilters;
180     if (!rClone.m_lChangedFrameLoaders.empty())
181         m_lFrameLoaders = rClone.m_lFrameLoaders;
182     if (!rClone.m_lChangedContentHandlers.empty())
183         m_lContentHandlers = rClone.m_lContentHandlers;
184 
185     m_lChangedTypes.clear();
186     m_lChangedFilters.clear();
187     m_lChangedFrameLoaders.clear();
188     m_lChangedContentHandlers.clear();
189 
190     m_sActLocale     = rClone.m_sActLocale;
191 
192     m_eFillState     = rClone.m_eFillState;
193 
194     // renew all dependencies and optimizations
195     // Because we can't be sure, that changed filters on one clone
196     // and changed types of another clone work together.
197     // But here we can check against the later changes...
198     impl_validateAndOptimize();
199     // <- SAFE ----------------------------------
200 }
201 
202 void FilterCache::load(EFillState eRequired)
203 {
204     // SAFE -> ----------------------------------
205     osl::MutexGuard aLock(m_aLock);
206 
207     // check if required fill state is already reached ...
208     // There is nothing to do then.
209     if ((m_eFillState & eRequired) == eRequired)
210         return;
211 
212     // Otherwise load the missing items.
213 
214 
215     // a) load some const values from configuration.
216     //    These values are needed there for loading
217     //    config items ...
218     //    Further we load some std items from the
219     //    configuration so we can try to load the first
220     //    office document with a minimal set of values.
221     if (m_eFillState == E_CONTAINS_NOTHING)
222     {
223         impl_getDirectCFGValue(CFGDIRECTKEY_OFFICELOCALE) >>= m_sActLocale;
224         if (m_sActLocale.isEmpty())
225         {
226             m_sActLocale = DEFAULT_OFFICELOCALE;
227         }
228 
229         // Support the old configuration support. Read it only one times during office runtime!
230         impl_readOldFormat();
231     }
232 
233 
234     // b) If the required fill state was not reached
235     //    but std values was already loaded ...
236     //    we must load some further missing items.
237     impl_load(eRequired);
238     // <- SAFE
239 }
240 
241 bool FilterCache::isFillState(FilterCache::EFillState eState) const
242 {
243     // SAFE ->
244     osl::MutexGuard aLock(m_aLock);
245     return ((m_eFillState & eState) == eState);
246     // <- SAFE
247 }
248 
249 
250 std::vector<OUString> FilterCache::getMatchingItemsByProps(      EItemType  eType  ,
251                                                   const CacheItem& lIProps,
252                                                   const CacheItem& lEProps) const
253 {
254     // SAFE ->
255     osl::MutexGuard aLock(m_aLock);
256 
257     // search for right list
258     // An exception is thrown - "eType" is unknown.
259     // => rList will be valid everytimes next line is reached.
260     const CacheItemList& rList = impl_getItemList(eType);
261 
262     std::vector<OUString> lKeys;
263 
264     // search items, which provides all needed properties of set "lIProps"
265     // but not of set "lEProps"!
266     for (auto const& elem : rList)
267     {
268         if (
269             (elem.second.haveProps(lIProps)    ) &&
270             (elem.second.dontHaveProps(lEProps))
271            )
272         {
273             lKeys.push_back(elem.first);
274         }
275     }
276 
277     return lKeys;
278     // <- SAFE
279 }
280 
281 
282 bool FilterCache::hasItems(EItemType eType) const
283 {
284     // SAFE ->
285     osl::MutexGuard aLock(m_aLock);
286 
287     // search for right list
288     // An exception is thrown - "eType" is unknown.
289     // => rList will be valid everytimes next line is reached.
290     const CacheItemList& rList = impl_getItemList(eType);
291 
292     return !rList.empty();
293     // <- SAFE
294 }
295 
296 
297 std::vector<OUString> FilterCache::getItemNames(EItemType eType) const
298 {
299     // SAFE ->
300     osl::MutexGuard aLock(m_aLock);
301 
302     // search for right list
303     // An exception is thrown - "eType" is unknown.
304     // => rList will be valid everytimes next line is reached.
305     const CacheItemList& rList = impl_getItemList(eType);
306 
307     std::vector<OUString> lKeys;
308     for (auto const& elem : rList)
309     {
310         lKeys.push_back(elem.first);
311     }
312     return lKeys;
313     // <- SAFE
314 }
315 
316 
317 bool FilterCache::hasItem(      EItemType        eType,
318                               const OUString& sItem)
319 {
320     // SAFE ->
321     osl::MutexGuard aLock(m_aLock);
322 
323     // search for right list
324     // An exception is thrown - "eType" is unknown.
325     // => rList will be valid everytimes next line is reached.
326     const CacheItemList& rList = impl_getItemList(eType);
327 
328     // if item could not be found - check if it can be loaded
329     // from the underlying configuration layer. Might it was not already
330     // loaded into this FilterCache object before.
331     CacheItemList::const_iterator pIt = rList.find(sItem);
332     if (pIt != rList.end())
333         return true;
334 
335     try
336     {
337         impl_loadItemOnDemand(eType, sItem);
338         // no exception => item could be loaded!
339         return true;
340     }
341     catch(const css::container::NoSuchElementException&)
342     {}
343 
344     return false;
345     // <- SAFE
346 }
347 
348 
349 CacheItem FilterCache::getItem(      EItemType        eType,
350                                const OUString& sItem)
351 {
352     // SAFE ->
353     osl::MutexGuard aLock(m_aLock);
354 
355     // search for right list
356     // An exception is thrown if "eType" is unknown.
357     // => rList will be valid everytimes next line is reached.
358     CacheItemList& rList = impl_getItemList(eType);
359 
360     // check if item exists ...
361     CacheItemList::iterator pIt = rList.find(sItem);
362     if (pIt == rList.end())
363     {
364         // ... or load it on demand from the
365         // underlying configuration layer.
366         // Note: NoSuchElementException is thrown automatically here if
367         // item could not be loaded!
368         pIt = impl_loadItemOnDemand(eType, sItem);
369     }
370 
371     /* Workaround for #137955#
372        Draw types and filters are installed ... but draw was disabled during setup.
373        We must suppress accessing these filters. Otherwise the office can crash.
374        Solution for the next major release: do not install those filters !
375      */
376     if (eType == E_FILTER)
377     {
378         CacheItem& rFilter = pIt->second;
379         OUString sDocService;
380         rFilter[PROPNAME_DOCUMENTSERVICE] >>= sDocService;
381 
382         // In Standalone-Impress the module WriterWeb is not installed
383         // but it is there to load help pages
384         bool bIsHelpFilter = sItem == "writer_web_HTML_help";
385 
386         if ( !bIsHelpFilter && !impl_isModuleInstalled(sDocService) )
387         {
388             OUString sMsg("The requested filter '" + sItem +
389                           "' exists ... but it should not; because the corresponding LibreOffice module was not installed.");
390             throw css::container::NoSuchElementException(sMsg, css::uno::Reference< css::uno::XInterface >());
391         }
392     }
393 
394     return pIt->second;
395     // <- SAFE
396 }
397 
398 
399 void FilterCache::removeItem(      EItemType        eType,
400                              const OUString& sItem)
401 {
402     // SAFE ->
403     osl::MutexGuard aLock(m_aLock);
404 
405     // search for right list
406     // An exception is thrown - "eType" is unknown.
407     // => rList will be valid everytimes next line is reached.
408     CacheItemList& rList = impl_getItemList(eType);
409 
410     CacheItemList::iterator pItem = rList.find(sItem);
411     if (pItem == rList.end())
412         pItem = impl_loadItemOnDemand(eType, sItem); // throws NoSuchELementException!
413     rList.erase(pItem);
414 
415     impl_addItem2FlushList(eType, sItem);
416 }
417 
418 
419 void FilterCache::setItem(      EItemType        eType ,
420                           const OUString& sItem ,
421                           const CacheItem&       aValue)
422 {
423     // SAFE ->
424     osl::MutexGuard aLock(m_aLock);
425 
426     // search for right list
427     // An exception is thrown - "eType" is unknown.
428     // => rList will be valid everytimes next line is reached.
429     CacheItemList& rList = impl_getItemList(eType);
430 
431     // name must be part of the property set too ... otherwise our
432     // container query can't work correctly
433     CacheItem aItem = aValue;
434     aItem[PROPNAME_NAME] <<= sItem;
435     aItem.validateUINames(m_sActLocale);
436 
437     // remove implicit properties as e.g. FINALIZED or MANDATORY
438     // They can't be saved here and must be read on demand later, if they are needed.
439     removeStatePropsFromItem(aItem);
440 
441     rList[sItem] = aItem;
442 
443     impl_addItem2FlushList(eType, sItem);
444 }
445 
446 
447 void FilterCache::refreshItem(      EItemType        eType,
448                               const OUString& sItem)
449 {
450     // SAFE ->
451     osl::MutexGuard aLock(m_aLock);
452     impl_loadItemOnDemand(eType, sItem);
453 }
454 
455 
456 void FilterCache::addStatePropsToItem(      EItemType        eType,
457                                       const OUString& sItem,
458                                             CacheItem&       rItem)
459 {
460     // SAFE ->
461     osl::MutexGuard aLock(m_aLock);
462 
463     // Note: Opening of the configuration layer throws some exceptions
464     // if it failed. So we mustn't check any reference here...
465     css::uno::Reference< css::container::XNameAccess > xPackage;
466     css::uno::Reference< css::container::XNameAccess > xSet;
467     switch(eType)
468     {
469         case E_TYPE :
470             {
471                 xPackage.set(impl_openConfig(E_PROVIDER_TYPES), css::uno::UNO_QUERY_THROW);
472                 xPackage->getByName(CFGSET_TYPES) >>= xSet;
473             }
474             break;
475 
476         case E_FILTER :
477             {
478                 xPackage.set(impl_openConfig(E_PROVIDER_FILTERS), css::uno::UNO_QUERY_THROW);
479                 xPackage->getByName(CFGSET_FILTERS) >>= xSet;
480             }
481             break;
482 
483         case E_FRAMELOADER :
484             {
485                 /* TODO
486                     Hack -->
487                         The default frame loader can't be located inside the normal set of frame loaders.
488                         It's an atomic property inside the misc cfg package. So we can't retrieve the information
489                         about FINALIZED and MANDATORY very easy ... :-(
490                         => set it to readonly/required everytimes :-)
491                 */
492                 css::uno::Any   aDirectValue       = impl_getDirectCFGValue(CFGDIRECTKEY_DEFAULTFRAMELOADER);
493                 OUString sDefaultFrameLoader;
494                 if (
495                     (aDirectValue >>= sDefaultFrameLoader) &&
496                     (!sDefaultFrameLoader.isEmpty()      ) &&
497                     (sItem == sDefaultFrameLoader   )
498                    )
499                 {
500                     rItem[PROPNAME_FINALIZED] <<= true;
501                     rItem[PROPNAME_MANDATORY] <<= true;
502                     return;
503                 }
504                 /* <-- HACK */
505 
506                 xPackage.set(impl_openConfig(E_PROVIDER_OTHERS), css::uno::UNO_QUERY_THROW);
507                 xPackage->getByName(CFGSET_FRAMELOADERS) >>= xSet;
508             }
509             break;
510 
511         case E_CONTENTHANDLER :
512             {
513                 xPackage.set(impl_openConfig(E_PROVIDER_OTHERS), css::uno::UNO_QUERY_THROW);
514                 xPackage->getByName(CFGSET_CONTENTHANDLERS) >>= xSet;
515             }
516             break;
517         default: break;
518     }
519 
520     try
521     {
522         css::uno::Reference< css::beans::XProperty > xItem;
523         xSet->getByName(sItem) >>= xItem;
524         css::beans::Property aDescription = xItem->getAsProperty();
525 
526         bool bFinalized = ((aDescription.Attributes & css::beans::PropertyAttribute::READONLY  ) == css::beans::PropertyAttribute::READONLY  );
527         bool bMandatory = ((aDescription.Attributes & css::beans::PropertyAttribute::REMOVABLE) != css::beans::PropertyAttribute::REMOVABLE);
528 
529         rItem[PROPNAME_FINALIZED] <<= bFinalized;
530         rItem[PROPNAME_MANDATORY] <<= bMandatory;
531     }
532     catch(const css::container::NoSuchElementException&)
533     {
534         /*  Ignore exceptions for missing elements inside configuration.
535             May by the following reason exists:
536                 -   The item does not exists inside the new configuration package org.openoffice.TypeDetection - but
537                     we got it from the old package org.openoffice.Office/TypeDetection. We don't migrate such items
538                     automatically to the new format. Because it will disturb e.g. the deinstallation of an external filter
539                     package. Because such external filter can remove the old file - but not the automatically created new one ...
540 
541             => mark item as FINALIZED / MANDATORY, we don't support writing to the old format
542         */
543         rItem[PROPNAME_FINALIZED] <<= true;
544         rItem[PROPNAME_MANDATORY] <<= true;
545     }
546 
547     // <- SAFE
548 }
549 
550 
551 void FilterCache::removeStatePropsFromItem(CacheItem& rItem)
552 {
553     CacheItem::iterator pIt = rItem.find(PROPNAME_FINALIZED);
554     if (pIt != rItem.end())
555         rItem.erase(pIt);
556     pIt = rItem.find(PROPNAME_MANDATORY);
557     if (pIt != rItem.end())
558         rItem.erase(pIt);
559 }
560 
561 
562 void FilterCache::flush()
563 {
564     // SAFE ->
565     osl::MutexGuard aLock(m_aLock);
566 
567     // renew all dependencies and optimizations
568     impl_validateAndOptimize();
569 
570     if (!m_lChangedTypes.empty())
571     {
572         css::uno::Reference< css::container::XNameAccess > xConfig(impl_openConfig(E_PROVIDER_TYPES), css::uno::UNO_QUERY_THROW);
573         css::uno::Reference< css::container::XNameAccess > xSet   ;
574 
575         xConfig->getByName(CFGSET_TYPES) >>= xSet;
576         impl_flushByList(xSet, E_TYPE, m_lTypes, m_lChangedTypes);
577 
578         css::uno::Reference< css::util::XChangesBatch > xFlush(xConfig, css::uno::UNO_QUERY);
579         xFlush->commitChanges();
580     }
581 
582     if (!m_lChangedFilters.empty())
583     {
584         css::uno::Reference< css::container::XNameAccess > xConfig(impl_openConfig(E_PROVIDER_FILTERS), css::uno::UNO_QUERY_THROW);
585         css::uno::Reference< css::container::XNameAccess > xSet   ;
586 
587         xConfig->getByName(CFGSET_FILTERS) >>= xSet;
588         impl_flushByList(xSet, E_FILTER, m_lFilters, m_lChangedFilters);
589 
590         css::uno::Reference< css::util::XChangesBatch > xFlush(xConfig, css::uno::UNO_QUERY);
591         xFlush->commitChanges();
592     }
593 
594     /*TODO FrameLoader/ContentHandler must be flushed here too ... */
595 }
596 
597 
598 void FilterCache::impl_flushByList(const css::uno::Reference< css::container::XNameAccess >& xSet  ,
599                                          EItemType                                           eType ,
600                                    const CacheItemList&                                      rCache,
601                                    const std::vector<OUString>&                              lItems)
602 {
603     css::uno::Reference< css::container::XNameContainer >   xAddRemoveSet(xSet, css::uno::UNO_QUERY);
604     css::uno::Reference< css::lang::XSingleServiceFactory > xFactory(xSet, css::uno::UNO_QUERY);
605 
606     for (auto const& item : lItems)
607     {
608         EItemFlushState  eState = impl_specifyFlushOperation(xSet, rCache, item);
609         switch(eState)
610         {
611             case E_ITEM_REMOVED :
612             {
613                 xAddRemoveSet->removeByName(item);
614             }
615             break;
616 
617             case E_ITEM_ADDED :
618             {
619                 css::uno::Reference< css::container::XNameReplace > xItem (xFactory->createInstance(), css::uno::UNO_QUERY);
620 
621                 // special case. no exception - but not a valid item => set must be finalized or mandatory!
622                 // Reject flush operation by throwing an exception. At least one item couldn't be flushed.
623                 if (!xItem.is())
624                     throw css::uno::Exception("Can not add item. Set is finalized or mandatory!",
625                                               css::uno::Reference< css::uno::XInterface >());
626 
627                 CacheItemList::const_iterator pItem = rCache.find(item);
628                 impl_saveItem(xItem, eType, pItem->second);
629                 xAddRemoveSet->insertByName(item, css::uno::makeAny(xItem));
630             }
631             break;
632 
633             case E_ITEM_CHANGED :
634             {
635                 css::uno::Reference< css::container::XNameReplace > xItem;
636                 xSet->getByName(item) >>= xItem;
637 
638                 // special case. no exception - but not a valid item => it must be finalized or mandatory!
639                 // Reject flush operation by throwing an exception. At least one item couldn't be flushed.
640                 if (!xItem.is())
641                     throw css::uno::Exception("Can not change item. It's finalized or mandatory!",
642                                               css::uno::Reference< css::uno::XInterface >());
643 
644                 CacheItemList::const_iterator pItem = rCache.find(item);
645                 impl_saveItem(xItem, eType, pItem->second);
646             }
647             break;
648             default: break;
649         }
650     }
651 }
652 
653 
654 void FilterCache::detectFlatForURL(const css::util::URL& aURL      ,
655                                          FlatDetection&  rFlatTypes) const
656 {
657     // extract extension from URL, so it can be used directly as key into our hash map!
658     // Note further: It must be converted to lower case, because the optimize hash
659     // (which maps extensions to types) work with lower case key strings!
660     INetURLObject   aParser    (aURL.Main);
661     OUString sExtension = aParser.getExtension(INetURLObject::LAST_SEGMENT       ,
662                                                       true                          ,
663                                                       INetURLObject::DecodeMechanism::WithCharset);
664     sExtension = sExtension.toAsciiLowerCase();
665 
666     // SAFE -> ----------------------------------
667     osl::MutexGuard aLock(m_aLock);
668 
669 
670     // i) Step over all well known URL pattern
671     //    and add registered types to the return list too
672     //    Do it as first one - because: if a type match by a
673     //    pattern a following deep detection can be suppressed!
674     //    Further we can stop after first match ...
675     for (auto const& pattern : m_lURLPattern2Types)
676     {
677         WildCard aPatternCheck(pattern.first);
678         if (aPatternCheck.Matches(aURL.Main))
679         {
680             const std::vector<OUString>& rTypesForPattern = pattern.second;
681 
682             FlatDetectionInfo aInfo;
683             aInfo.sType = *(rTypesForPattern.begin());
684             aInfo.bMatchByPattern = true;
685 
686             rFlatTypes.push_back(aInfo);
687 //          return;
688         }
689     }
690 
691 
692     // ii) search types matching to the given extension.
693     //     Copy every matching type without changing its order!
694     //     Because preferred types was added as first one during
695     //     loading configuration.
696     CacheItemRegistration::const_iterator pExtReg = m_lExtensions2Types.find(sExtension);
697     if (pExtReg != m_lExtensions2Types.end())
698     {
699         const std::vector<OUString>& rTypesForExtension = pExtReg->second;
700         for (auto const& elem : rTypesForExtension)
701         {
702             FlatDetectionInfo aInfo;
703             aInfo.sType             = elem;
704             aInfo.bMatchByExtension = true;
705 
706             rFlatTypes.push_back(aInfo);
707         }
708     }
709 
710     // <- SAFE ----------------------------------
711 }
712 
713 const CacheItemList& FilterCache::impl_getItemList(EItemType eType) const
714 {
715     // SAFE -> ----------------------------------
716     osl::MutexGuard aLock(m_aLock);
717 
718     switch(eType)
719     {
720         case E_TYPE           : return m_lTypes          ;
721         case E_FILTER         : return m_lFilters        ;
722         case E_FRAMELOADER    : return m_lFrameLoaders   ;
723         case E_CONTENTHANDLER : return m_lContentHandlers;
724 
725     }
726 
727     throw css::uno::RuntimeException("unknown sub container requested.",
728                                             css::uno::Reference< css::uno::XInterface >());
729     // <- SAFE ----------------------------------
730 }
731 
732 CacheItemList& FilterCache::impl_getItemList(EItemType eType)
733 {
734     // SAFE -> ----------------------------------
735     osl::MutexGuard aLock(m_aLock);
736 
737     switch(eType)
738     {
739         case E_TYPE           : return m_lTypes          ;
740         case E_FILTER         : return m_lFilters        ;
741         case E_FRAMELOADER    : return m_lFrameLoaders   ;
742         case E_CONTENTHANDLER : return m_lContentHandlers;
743 
744     }
745 
746     throw css::uno::RuntimeException("unknown sub container requested.",
747                                             css::uno::Reference< css::uno::XInterface >());
748     // <- SAFE ----------------------------------
749 }
750 
751 css::uno::Reference< css::uno::XInterface > FilterCache::impl_openConfig(EConfigProvider eProvider)
752 {
753     osl::MutexGuard aLock(m_aLock);
754 
755     OUString                              sPath      ;
756     css::uno::Reference< css::uno::XInterface >* pConfig = nullptr;
757     css::uno::Reference< css::uno::XInterface >  xOld       ;
758     OString                               sRtlLog    ;
759 
760     switch(eProvider)
761     {
762         case E_PROVIDER_TYPES :
763         {
764             if (m_xConfigTypes.is())
765                 return m_xConfigTypes;
766             sPath           = CFGPACKAGE_TD_TYPES;
767             pConfig         = &m_xConfigTypes;
768             sRtlLog         = "impl_openconfig(E_PROVIDER_TYPES)";
769         }
770         break;
771 
772         case E_PROVIDER_FILTERS :
773         {
774             if (m_xConfigFilters.is())
775                 return m_xConfigFilters;
776             sPath           = CFGPACKAGE_TD_FILTERS;
777             pConfig         = &m_xConfigFilters;
778             sRtlLog         = "impl_openconfig(E_PROVIDER_FILTERS)";
779         }
780         break;
781 
782         case E_PROVIDER_OTHERS :
783         {
784             if (m_xConfigOthers.is())
785                 return m_xConfigOthers;
786             sPath   = CFGPACKAGE_TD_OTHERS;
787             pConfig = &m_xConfigOthers;
788             sRtlLog = "impl_openconfig(E_PROVIDER_OTHERS)";
789         }
790         break;
791 
792         case E_PROVIDER_OLD :
793         {
794             // This special provider is used to work with
795             // the old configuration format only. It's not cached!
796             sPath   = CFGPACKAGE_TD_OLD;
797             pConfig = &xOld;
798             sRtlLog = "impl_openconfig(E_PROVIDER_OLD)";
799         }
800         break;
801 
802         default : throw css::uno::RuntimeException("These configuration node is not supported here for open!", nullptr);
803     }
804 
805     {
806         SAL_INFO( "filter.config", "" << sRtlLog);
807         *pConfig = impl_createConfigAccess(sPath    ,
808                                            false,   // bReadOnly
809                                            true );  // bLocalesMode
810     }
811 
812 
813     // Start listening for changes on that configuration access.
814     switch(eProvider)
815     {
816         case E_PROVIDER_TYPES:
817         {
818             m_xTypesChglisteners.set(new CacheUpdateListener(*this, *pConfig, FilterCache::E_TYPE));
819             m_xTypesChglisteners->startListening();
820         }
821         break;
822         case E_PROVIDER_FILTERS:
823         {
824             m_xFiltersChgListener.set(new CacheUpdateListener(*this, *pConfig, FilterCache::E_FILTER));
825             m_xFiltersChgListener->startListening();
826         }
827         break;
828         default:
829         break;
830     }
831 
832     return *pConfig;
833 }
834 
835 css::uno::Any FilterCache::impl_getDirectCFGValue(const OUString& sDirectKey)
836 {
837     OUString sRoot;
838     OUString sKey ;
839 
840     if (
841         (!::utl::splitLastFromConfigurationPath(sDirectKey, sRoot, sKey)) ||
842         (sRoot.isEmpty()                                             ) ||
843         (sKey.isEmpty()                                              )
844        )
845         return css::uno::Any();
846 
847     css::uno::Reference< css::uno::XInterface > xCfg = impl_createConfigAccess(sRoot    ,
848                                                                                true ,  // bReadOnly
849                                                                                false); // bLocalesMode
850     if (!xCfg.is())
851         return css::uno::Any();
852 
853     css::uno::Reference< css::container::XNameAccess > xAccess(xCfg, css::uno::UNO_QUERY);
854     if (!xAccess.is())
855         return css::uno::Any();
856 
857     css::uno::Any aValue;
858     try
859     {
860         aValue = xAccess->getByName(sKey);
861     }
862     catch(const css::uno::RuntimeException&)
863         { throw; }
864     catch(const css::uno::Exception&)
865         {
866             TOOLS_WARN_EXCEPTION( "filter.config", "");
867             aValue.clear();
868         }
869 
870     return aValue;
871 }
872 
873 
874 css::uno::Reference< css::uno::XInterface > FilterCache::impl_createConfigAccess(const OUString& sRoot       ,
875                                                                                        bool         bReadOnly   ,
876                                                                                        bool         bLocalesMode)
877 {
878     // SAFE ->
879     osl::MutexGuard aLock(m_aLock);
880 
881     css::uno::Reference< css::uno::XInterface > xCfg;
882 
883     if (!utl::ConfigManager::IsFuzzing())
884     {
885         try
886         {
887             css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider(
888                 css::configuration::theDefaultProvider::get( comphelper::getProcessComponentContext() ) );
889 
890             ::std::vector< css::uno::Any > lParams;
891             css::beans::NamedValue aParam;
892 
893             // set root path
894             aParam.Name = "nodepath";
895             aParam.Value <<= sRoot;
896             lParams.push_back(css::uno::makeAny(aParam));
897 
898             // enable "all locales mode" ... if required
899             if (bLocalesMode)
900             {
901                 aParam.Name = "locale";
902                 aParam.Value <<= OUString("*");
903                 lParams.push_back(css::uno::makeAny(aParam));
904             }
905 
906             // open it
907             if (bReadOnly)
908                 xCfg = xConfigProvider->createInstanceWithArguments(SERVICE_CONFIGURATIONACCESS,
909                         comphelper::containerToSequence(lParams));
910             else
911                 xCfg = xConfigProvider->createInstanceWithArguments(SERVICE_CONFIGURATIONUPDATEACCESS,
912                         comphelper::containerToSequence(lParams));
913 
914             // If configuration could not be opened... but factory method did not throw an exception
915             // trigger throwing of our own CorruptedFilterConfigurationException.
916             // Let message empty. The normal exception text show enough information to the user.
917             if (! xCfg.is())
918                 throw css::uno::Exception(
919                         "Got NULL reference on opening configuration file ... but no exception.",
920                         css::uno::Reference< css::uno::XInterface >());
921         }
922         catch(const css::uno::Exception& ex)
923         {
924             throw css::document::CorruptedFilterConfigurationException(
925                     "filter configuration, caught: " + ex.Message,
926                     css::uno::Reference< css::uno::XInterface >(),
927                     ex.Message);
928         }
929     }
930 
931     return xCfg;
932     // <- SAFE
933 }
934 
935 
936 void FilterCache::impl_validateAndOptimize()
937 {
938     // SAFE ->
939     osl::MutexGuard aLock(m_aLock);
940 
941     // First check if any filter or type could be read
942     // from the underlying configuration!
943     bool bSomeTypesShouldExist   = ((m_eFillState & E_CONTAINS_STANDARD       ) == E_CONTAINS_STANDARD       );
944     bool bAllFiltersShouldExist  = ((m_eFillState & E_CONTAINS_FILTERS        ) == E_CONTAINS_FILTERS        );
945 
946 #if OSL_DEBUG_LEVEL > 0
947 
948     sal_Int32             nWarnings = 0;
949 
950 //  sal_Bool bAllTypesShouldExist    = ((m_eFillState & E_CONTAINS_TYPES          ) == E_CONTAINS_TYPES          );
951     bool bAllLoadersShouldExist  = ((m_eFillState & E_CONTAINS_FRAMELOADERS   ) == E_CONTAINS_FRAMELOADERS   );
952     bool bAllHandlersShouldExist = ((m_eFillState & E_CONTAINS_CONTENTHANDLERS) == E_CONTAINS_CONTENTHANDLERS);
953 #endif
954 
955     if (
956         (
957             bSomeTypesShouldExist && m_lTypes.empty()
958         ) ||
959         (
960             bAllFiltersShouldExist && m_lFilters.empty()
961         )
962        )
963     {
964         throw css::document::CorruptedFilterConfigurationException(
965                 "filter configuration: the list of types or filters is empty",
966                 css::uno::Reference< css::uno::XInterface >(),
967                 "The list of types or filters is empty." );
968     }
969 
970     // Create a log for all detected problems, which
971     // occur in the next few lines.
972     // If there are some real errors throw a RuntimException!
973     // If there are some warnings only, show an assertion.
974     sal_Int32             nErrors   = 0;
975     OUStringBuffer sLog(256);
976 
977     for (auto const& elem : m_lTypes)
978     {
979         OUString sType = elem.first;
980         CacheItem aType = elem.second;
981 
982         // get its registration for file Extensions AND(!) URLPattern ...
983         // It doesn't matter if these items exists or if our
984         // used index access create some default ones ...
985         // only in case there is no filled set of Extensions AND
986         // no filled set of URLPattern -> we must try to remove this invalid item
987         // from this cache!
988         css::uno::Sequence< OUString > lExtensions;
989         css::uno::Sequence< OUString > lURLPattern;
990         aType[PROPNAME_EXTENSIONS] >>= lExtensions;
991         aType[PROPNAME_URLPATTERN] >>= lURLPattern;
992         sal_Int32 ce = lExtensions.getLength();
993         sal_Int32 cu = lURLPattern.getLength();
994 
995 #if OSL_DEBUG_LEVEL > 0
996 
997         OUString sInternalTypeNameCheck;
998         aType[PROPNAME_NAME] >>= sInternalTypeNameCheck;
999         if (sInternalTypeNameCheck != sType)
1000         {
1001             sLog.append("Warning\t:\t" "The type \"").append(sType).append("\" does support the property \"Name\" correctly.\n");
1002             ++nWarnings;
1003         }
1004 
1005         if (!ce && !cu)
1006         {
1007             sLog.append("Warning\t:\t" "The type \"").append(sType).append("\" does not contain any URL pattern nor any extensions.\n");
1008             ++nWarnings;
1009         }
1010 #endif
1011 
1012         // create an optimized registration for this type to
1013         // its set list of extensions/url pattern. If it's a "normal" type
1014         // set it at the end of this optimized list. But if its
1015         // a "Preferred" one - set it to the front of this list.
1016         // Of course multiple "Preferred" registrations can occur
1017         // (they shouldn't - but they can!) ... Ignore it. The last
1018         // preferred type is usable in the same manner then every
1019         // other type!
1020         bool bPreferred = false;
1021         aType[PROPNAME_PREFERRED] >>= bPreferred;
1022 
1023         const OUString* pExtensions = lExtensions.getConstArray();
1024         for (sal_Int32 e=0; e<ce; ++e)
1025         {
1026             // Note: We must be sure that address the right hash entry
1027             // does not depend from any upper/lower case problems ...
1028             OUString sNormalizedExtension = pExtensions[e].toAsciiLowerCase();
1029 
1030             std::vector<OUString>& lTypesForExtension = m_lExtensions2Types[sNormalizedExtension];
1031             if (::std::find(lTypesForExtension.begin(), lTypesForExtension.end(), sType) != lTypesForExtension.end())
1032                 continue;
1033 
1034             if (bPreferred)
1035                 lTypesForExtension.insert(lTypesForExtension.begin(), sType);
1036             else
1037                 lTypesForExtension.push_back(sType);
1038         }
1039 
1040         const OUString* pURLPattern = lURLPattern.getConstArray();
1041         for (sal_Int32 u=0; u<cu; ++u)
1042         {
1043             std::vector<OUString>& lTypesForURLPattern = m_lURLPattern2Types[pURLPattern[u]];
1044             if (::std::find(lTypesForURLPattern.begin(), lTypesForURLPattern.end(), sType) != lTypesForURLPattern.end())
1045                 continue;
1046 
1047             if (bPreferred)
1048                 lTypesForURLPattern.insert(lTypesForURLPattern.begin(), sType);
1049             else
1050                 lTypesForURLPattern.push_back(sType);
1051         }
1052 
1053 #if OSL_DEBUG_LEVEL > 0
1054 
1055         // Don't check cross references between types and filters, if
1056         // not all filters read from disk!
1057         // OK - this cache can read single filters on demand too ...
1058         // but then the fill state of this cache should not be set to E_CONTAINS_FILTERS!
1059         if (!bAllFiltersShouldExist)
1060             continue;
1061 
1062         OUString sPrefFilter;
1063         aType[PROPNAME_PREFERREDFILTER] >>= sPrefFilter;
1064         if (sPrefFilter.isEmpty())
1065         {
1066             // OK - there is no filter for this type. But that's not an error.
1067             // Maybe it can be handled by a ContentHandler...
1068             // But at this time it's not guaranteed that there is any ContentHandler
1069             // or FrameLoader inside this cache... but on disk...
1070             bool bReferencedByLoader  = true;
1071             bool bReferencedByHandler = true;
1072             if (bAllLoadersShouldExist)
1073                 bReferencedByLoader = !impl_searchFrameLoaderForType(sType).isEmpty();
1074 
1075             if (bAllHandlersShouldExist)
1076                 bReferencedByHandler = !impl_searchContentHandlerForType(sType).isEmpty();
1077 
1078             if (
1079                 (!bReferencedByLoader ) &&
1080                 (!bReferencedByHandler)
1081                )
1082             {
1083                 sLog.append("Warning\t:\t" "The type \"").append(sType).append("\" is not used by any filter, loader or content handler.\n");
1084                 ++nWarnings;
1085             }
1086         }
1087 
1088         if (!sPrefFilter.isEmpty())
1089         {
1090             CacheItemList::const_iterator pIt2 = m_lFilters.find(sPrefFilter);
1091             if (pIt2 == m_lFilters.end())
1092             {
1093                 if (bAllFiltersShouldExist)
1094                 {
1095                     ++nWarnings; // preferred filters can point to a non-installed office module ! no error ... it's a warning only .-(
1096                     sLog.append("error\t:\t");
1097                 }
1098                 else
1099                 {
1100                     ++nWarnings;
1101                     sLog.append("warning\t:\t");
1102                 }
1103 
1104                 sLog.append("The type \"").append(sType).append("\" points to an invalid filter \"").append(sPrefFilter).append("\".\n");
1105                 continue;
1106             }
1107 
1108             CacheItem       aPrefFilter   = pIt2->second;
1109             OUString sFilterTypeReg;
1110             aPrefFilter[PROPNAME_TYPE] >>= sFilterTypeReg;
1111             if (sFilterTypeReg != sType)
1112             {
1113                 sLog.append("error\t:\t" "The preferred filter \"")
1114                     .append(sPrefFilter).append("\" of type \"").append(sType)
1115                     .append("\" is registered for another type \"").append(sFilterTypeReg)
1116                     .append("\".\n");
1117                 ++nErrors;
1118             }
1119 
1120             sal_Int32 nFlags = 0;
1121             aPrefFilter[PROPNAME_FLAGS] >>= nFlags;
1122             if (!(static_cast<SfxFilterFlags>(nFlags) & SfxFilterFlags::IMPORT))
1123             {
1124                 sLog.append("error\t:\t" "The preferred filter \"").append(sPrefFilter).append("\" of type \"")
1125                             .append(sType).append("\" is not an IMPORT filter!\n");
1126                 ++nErrors;
1127             }
1128 
1129             OUString sInternalFilterNameCheck;
1130             aPrefFilter[PROPNAME_NAME] >>= sInternalFilterNameCheck;
1131             if (sInternalFilterNameCheck !=  sPrefFilter)
1132             {
1133                 sLog.append("Warning\t:\t" "The filter \"").append(sPrefFilter)
1134                             .append("\" does support the property \"Name\" correctly.\n");
1135                 ++nWarnings;
1136             }
1137         }
1138 #endif
1139     }
1140 
1141     // create dependencies between the global default frame loader
1142     // and all types (and of course if registered filters), which
1143     // does not registered for any other loader.
1144     css::uno::Any   aDirectValue       = impl_getDirectCFGValue(CFGDIRECTKEY_DEFAULTFRAMELOADER);
1145     OUString sDefaultFrameLoader;
1146 
1147     if (
1148         (!(aDirectValue >>= sDefaultFrameLoader)) ||
1149         (sDefaultFrameLoader.isEmpty()       )
1150        )
1151     {
1152         sLog.append("error\t:\t" "There is no valid default frame loader!?\n");
1153         ++nErrors;
1154     }
1155 
1156     // a) get list of all well known types
1157     // b) step over all well known frame loader services
1158     //    and remove all types from list a), which already
1159     //    referenced by a loader b)
1160     std::vector<OUString> lTypes = getItemNames(E_TYPE);
1161     for (auto & frameLoader : m_lFrameLoaders)
1162     {
1163         // Note: of course the default loader must be ignored here.
1164         // Because we replace its registration later completely with all
1165         // types, which are not referenced by any other loader.
1166         // So we can avoid our code against the complexity of a diff!
1167         OUString sLoader = frameLoader.first;
1168         if (sLoader == sDefaultFrameLoader)
1169             continue;
1170 
1171         CacheItem&     rLoader   = frameLoader.second;
1172         css::uno::Any& rTypesReg = rLoader[PROPNAME_TYPES];
1173         std::vector<OUString>   lTypesReg (comphelper::sequenceToContainer< std::vector<OUString> >(rTypesReg.get<css::uno::Sequence<OUString> >()));
1174 
1175         for (auto const& typeReg : lTypesReg)
1176         {
1177             auto pTypeCheck = ::std::find(lTypes.begin(), lTypes.end(), typeReg);
1178             if (pTypeCheck != lTypes.end())
1179                 lTypes.erase(pTypeCheck);
1180         }
1181     }
1182 
1183     CacheItem& rDefaultLoader = m_lFrameLoaders[sDefaultFrameLoader];
1184     rDefaultLoader[PROPNAME_NAME ] <<= sDefaultFrameLoader;
1185     rDefaultLoader[PROPNAME_TYPES] <<= comphelper::containerToSequence(lTypes);
1186 
1187     OUString sLogOut = sLog.makeStringAndClear();
1188     OSL_ENSURE(!nErrors, OUStringToOString(sLogOut,RTL_TEXTENCODING_UTF8).getStr());
1189     if (nErrors>0)
1190         throw css::document::CorruptedFilterConfigurationException(
1191                 "filter configuration: " + sLogOut,
1192                 css::uno::Reference< css::uno::XInterface >(),
1193                 sLogOut);
1194 #if OSL_DEBUG_LEVEL > 0
1195     OSL_ENSURE(!nWarnings, OUStringToOString(sLogOut,RTL_TEXTENCODING_UTF8).getStr());
1196 #endif
1197 
1198     // <- SAFE
1199 }
1200 
1201 void FilterCache::impl_addItem2FlushList(      EItemType        eType,
1202                                          const OUString& sItem)
1203 {
1204     std::vector<OUString>* pList = nullptr;
1205     switch(eType)
1206     {
1207         case E_TYPE :
1208                 pList = &m_lChangedTypes;
1209                 break;
1210 
1211         case E_FILTER :
1212                 pList = &m_lChangedFilters;
1213                 break;
1214 
1215         case E_FRAMELOADER :
1216                 pList = &m_lChangedFrameLoaders;
1217                 break;
1218 
1219         case E_CONTENTHANDLER :
1220                 pList = &m_lChangedContentHandlers;
1221                 break;
1222 
1223         default : throw css::uno::RuntimeException("unsupported item type", nullptr);
1224     }
1225 
1226     auto pItem = ::std::find(pList->cbegin(), pList->cend(), sItem);
1227     if (pItem == pList->cend())
1228         pList->push_back(sItem);
1229 }
1230 
1231 FilterCache::EItemFlushState FilterCache::impl_specifyFlushOperation(const css::uno::Reference< css::container::XNameAccess >& xSet ,
1232                                                                      const CacheItemList&                                      rList,
1233                                                                      const OUString&                                    sItem)
1234 {
1235     bool bExistsInConfigLayer = xSet->hasByName(sItem);
1236     bool bExistsInMemory      = (rList.find(sItem) != rList.end());
1237 
1238     EItemFlushState eState( E_ITEM_UNCHANGED );
1239 
1240     // !? ... such situation can occur, if an item was added and(!) removed before it was flushed :-)
1241     if (!bExistsInConfigLayer && !bExistsInMemory)
1242         eState = E_ITEM_UNCHANGED;
1243     else if (!bExistsInConfigLayer && bExistsInMemory)
1244         eState = E_ITEM_ADDED;
1245     else if (bExistsInConfigLayer && bExistsInMemory)
1246         eState = E_ITEM_CHANGED;
1247     else if (bExistsInConfigLayer && !bExistsInMemory)
1248         eState = E_ITEM_REMOVED;
1249 
1250     return eState;
1251 }
1252 
1253 void FilterCache::impl_load(EFillState eRequiredState)
1254 {
1255     // SAFE ->
1256     osl::MutexGuard aLock(m_aLock);
1257 
1258     // Attention: Detect services are part of the standard set!
1259     // So there is no need to handle it separately.
1260 
1261 
1262     // a) The standard set of config value is needed.
1263     if (
1264         ((eRequiredState & E_CONTAINS_STANDARD) == E_CONTAINS_STANDARD) &&
1265         ((m_eFillState   & E_CONTAINS_STANDARD) != E_CONTAINS_STANDARD)
1266        )
1267     {
1268         // Attention! If config couldn't be opened successfully
1269         // and exception os thrown automatically and must be forwarded
1270         // to our caller...
1271         css::uno::Reference< css::container::XNameAccess > xTypes(impl_openConfig(E_PROVIDER_TYPES), css::uno::UNO_QUERY_THROW);
1272         {
1273             SAL_INFO( "filter.config", "FilterCache::load std");
1274             impl_loadSet(xTypes, E_TYPE, E_READ_STANDARD, &m_lTypes);
1275         }
1276     }
1277 
1278 
1279     // b) We need all type information ...
1280     if (
1281         ((eRequiredState & E_CONTAINS_TYPES) == E_CONTAINS_TYPES) &&
1282         ((m_eFillState   & E_CONTAINS_TYPES) != E_CONTAINS_TYPES)
1283        )
1284     {
1285         // Attention! If config couldn't be opened successfully
1286         // and exception os thrown automatically and must be forwarded
1287         // to our call...
1288         css::uno::Reference< css::container::XNameAccess > xTypes(impl_openConfig(E_PROVIDER_TYPES), css::uno::UNO_QUERY_THROW);
1289         {
1290             SAL_INFO( "filter.config", "FilterCache::load all types");
1291             impl_loadSet(xTypes, E_TYPE, E_READ_UPDATE, &m_lTypes);
1292         }
1293     }
1294 
1295 
1296     // c) We need all filter information ...
1297     if (
1298         ((eRequiredState & E_CONTAINS_FILTERS) == E_CONTAINS_FILTERS) &&
1299         ((m_eFillState   & E_CONTAINS_FILTERS) != E_CONTAINS_FILTERS)
1300        )
1301     {
1302         // Attention! If config couldn't be opened successfully
1303         // and exception os thrown automatically and must be forwarded
1304         // to our call...
1305         css::uno::Reference< css::container::XNameAccess > xFilters(impl_openConfig(E_PROVIDER_FILTERS), css::uno::UNO_QUERY_THROW);
1306         {
1307             SAL_INFO( "filter.config", "FilterCache::load all filters");
1308             impl_loadSet(xFilters, E_FILTER, E_READ_ALL, &m_lFilters);
1309         }
1310     }
1311 
1312 
1313     // c) We need all frame loader information ...
1314     if (
1315         ((eRequiredState & E_CONTAINS_FRAMELOADERS) == E_CONTAINS_FRAMELOADERS) &&
1316         ((m_eFillState   & E_CONTAINS_FRAMELOADERS) != E_CONTAINS_FRAMELOADERS)
1317        )
1318     {
1319         // Attention! If config couldn't be opened successfully
1320         // and exception os thrown automatically and must be forwarded
1321         // to our call...
1322         css::uno::Reference< css::container::XNameAccess > xLoaders(impl_openConfig(E_PROVIDER_OTHERS), css::uno::UNO_QUERY_THROW);
1323         {
1324             SAL_INFO( "filter.config", "FilterCache::load all frame loader");
1325             impl_loadSet(xLoaders, E_FRAMELOADER, E_READ_ALL, &m_lFrameLoaders);
1326         }
1327     }
1328 
1329 
1330     // d) We need all content handler information...
1331     if (
1332         ((eRequiredState & E_CONTAINS_CONTENTHANDLERS) == E_CONTAINS_CONTENTHANDLERS) &&
1333         ((m_eFillState   & E_CONTAINS_CONTENTHANDLERS) != E_CONTAINS_CONTENTHANDLERS)
1334        )
1335     {
1336         // Attention! If config couldn't be opened successfully
1337         // and exception os thrown automatically and must be forwarded
1338         // to our call...
1339         css::uno::Reference< css::container::XNameAccess > xHandlers(impl_openConfig(E_PROVIDER_OTHERS), css::uno::UNO_QUERY_THROW);
1340         {
1341             SAL_INFO( "filter.config", "FilterCache::load all content handler");
1342             impl_loadSet(xHandlers, E_CONTENTHANDLER, E_READ_ALL, &m_lContentHandlers);
1343         }
1344     }
1345 
1346     // update fill state. Note: it's a bit field, which combines different parts.
1347     m_eFillState = static_cast<EFillState>(static_cast<sal_Int32>(m_eFillState) | static_cast<sal_Int32>(eRequiredState));
1348 
1349     // any data read?
1350     // yes! => validate it and update optimized structures.
1351     impl_validateAndOptimize();
1352 
1353     // <- SAFE
1354 }
1355 
1356 void FilterCache::impl_loadSet(const css::uno::Reference< css::container::XNameAccess >& xConfig,
1357                                      EItemType                                           eType  ,
1358                                      EReadOption                                         eOption,
1359                                      CacheItemList*                                      pCache )
1360 {
1361     // get access to the right configuration set
1362     OUString sSetName;
1363     switch(eType)
1364     {
1365         case E_TYPE :
1366             sSetName = CFGSET_TYPES;
1367             break;
1368 
1369         case E_FILTER :
1370             sSetName = CFGSET_FILTERS;
1371             break;
1372 
1373         case E_FRAMELOADER :
1374             sSetName = CFGSET_FRAMELOADERS;
1375             break;
1376 
1377         case E_CONTENTHANDLER :
1378             sSetName = CFGSET_CONTENTHANDLERS;
1379             break;
1380         default: break;
1381     }
1382 
1383     css::uno::Reference< css::container::XNameAccess > xSet;
1384     css::uno::Sequence< OUString >              lItems;
1385 
1386     try
1387     {
1388         css::uno::Any aVal = xConfig->getByName(sSetName);
1389         if (!(aVal >>= xSet) || !xSet.is())
1390         {
1391             OUString sMsg("Could not open configuration set \"" + sSetName + "\".");
1392             throw css::uno::Exception(sMsg, css::uno::Reference< css::uno::XInterface >());
1393         }
1394         lItems = xSet->getElementNames();
1395     }
1396     catch(const css::uno::Exception& ex)
1397     {
1398         throw css::document::CorruptedFilterConfigurationException(
1399                 "filter configuration, caught: " + ex.Message,
1400                 css::uno::Reference< css::uno::XInterface >(),
1401                 ex.Message);
1402     }
1403 
1404     // get names of all existing sub items of this set
1405     // step over it and fill internal cache structures.
1406 
1407     // But don't update optimized structures like e.g. hash
1408     // for mapping extensions to its types!
1409 
1410     const OUString* pItems = lItems.getConstArray();
1411     sal_Int32       c      = lItems.getLength();
1412     for (sal_Int32 i=0; i<c; ++i)
1413     {
1414         CacheItemList::iterator pItem = pCache->find(pItems[i]);
1415         switch(eOption)
1416         {
1417             // a) read a standard set of properties only or read all
1418             case E_READ_STANDARD :
1419             case E_READ_ALL      :
1420             {
1421                 try
1422                 {
1423                     (*pCache)[pItems[i]] = impl_loadItem(xSet, eType, pItems[i], eOption);
1424                 }
1425                 catch(const css::uno::Exception& ex)
1426                 {
1427                     throw css::document::CorruptedFilterConfigurationException(
1428                             "filter configuration, caught: " + ex.Message,
1429                             css::uno::Reference< css::uno::XInterface >(),
1430                             ex.Message);
1431                 }
1432             }
1433             break;
1434 
1435             // b) read optional properties only!
1436             //    All items must already exist inside our cache.
1437             //    But they must be updated.
1438             case E_READ_UPDATE :
1439             {
1440                 if (pItem == pCache->end())
1441                 {
1442                     OUString sMsg("item \"" + pItems[i] + "\" not found for update!");
1443                     throw css::uno::Exception(sMsg, css::uno::Reference< css::uno::XInterface >());
1444                 }
1445                 try
1446                 {
1447                     CacheItem aItem = impl_loadItem(xSet, eType, pItems[i], eOption);
1448                     pItem->second.update(aItem);
1449                 }
1450                 catch(const css::uno::Exception& ex)
1451                 {
1452                     throw css::document::CorruptedFilterConfigurationException(
1453                             "filter configuration, caught: " + ex.Message,
1454                             css::uno::Reference< css::uno::XInterface >(),
1455                             ex.Message);
1456                 }
1457             }
1458             break;
1459             default: break;
1460         }
1461     }
1462 }
1463 
1464 void FilterCache::impl_readPatchUINames(const css::uno::Reference< css::container::XNameAccess >& xNode,
1465                                               CacheItem&                                          rItem)
1466 {
1467 
1468     // SAFE -> ----------------------------------
1469     osl::ClearableMutexGuard aLock(m_aLock);
1470     OUString sActLocale     = m_sActLocale    ;
1471     aLock.clear();
1472     // <- SAFE ----------------------------------
1473 
1474     css::uno::Any aVal = xNode->getByName(PROPNAME_UINAME);
1475     css::uno::Reference< css::container::XNameAccess > xUIName;
1476     if (!(aVal >>= xUIName) && !xUIName.is())
1477         return;
1478 
1479     const ::std::vector< OUString >                 lLocales(comphelper::sequenceToContainer< ::std::vector< OUString >>(
1480                                                                 xUIName->getElementNames()));
1481     ::std::vector< OUString >::const_iterator pLocale ;
1482     ::comphelper::SequenceAsHashMap           lUINames;
1483 
1484     for (auto const& locale : lLocales)
1485     {
1486         OUString sValue;
1487         xUIName->getByName(locale) >>= sValue;
1488 
1489         lUINames[locale] <<= sValue;
1490     }
1491 
1492     aVal <<= lUINames.getAsConstPropertyValueList();
1493     rItem[PROPNAME_UINAMES] = aVal;
1494 
1495     // find right UIName for current office locale
1496     // Use fallbacks too!
1497     pLocale = LanguageTag::getFallback(lLocales, sActLocale);
1498     if (pLocale == lLocales.end())
1499     {
1500 #if OSL_DEBUG_LEVEL > 0
1501         if ( sActLocale == "en-US" )
1502             return;
1503         OUString sName = rItem.getUnpackedValueOrDefault(PROPNAME_NAME, OUString());
1504 
1505         SAL_WARN("filter.config", "Fallback scenario for filter or type '" << sName << "' and locale '" <<
1506                       sActLocale << "' failed. Please check your filter configuration.");
1507 #endif
1508         return;
1509     }
1510 
1511     const OUString& sLocale = *pLocale;
1512     ::comphelper::SequenceAsHashMap::const_iterator pUIName = lUINames.find(sLocale);
1513     if (pUIName != lUINames.end())
1514         rItem[PROPNAME_UINAME] = pUIName->second;
1515 }
1516 
1517 void FilterCache::impl_savePatchUINames(const css::uno::Reference< css::container::XNameReplace >& xNode,
1518                                         const CacheItem&                                           rItem)
1519 {
1520     css::uno::Reference< css::container::XNameContainer > xAdd  (xNode, css::uno::UNO_QUERY);
1521 
1522     css::uno::Sequence< css::beans::PropertyValue > lUINames = rItem.getUnpackedValueOrDefault(PROPNAME_UINAMES, css::uno::Sequence< css::beans::PropertyValue >());
1523     sal_Int32                                       c        = lUINames.getLength();
1524     const css::beans::PropertyValue*                pUINames = lUINames.getConstArray();
1525 
1526     for (sal_Int32 i=0; i<c; ++i)
1527     {
1528         if (xNode->hasByName(pUINames[i].Name))
1529             xNode->replaceByName(pUINames[i].Name, pUINames[i].Value);
1530         else
1531             xAdd->insertByName(pUINames[i].Name, pUINames[i].Value);
1532     }
1533 }
1534 
1535 /*-----------------------------------------------
1536     TODO
1537         clarify, how the real problem behind the
1538         wrong constructed CacheItem instance (which
1539         will force a crash during destruction)
1540         can be solved ...
1541 -----------------------------------------------*/
1542 CacheItem FilterCache::impl_loadItem(const css::uno::Reference< css::container::XNameAccess >& xSet   ,
1543                                            EItemType                                           eType  ,
1544                                      const OUString&                                    sItem  ,
1545                                            EReadOption                                         eOption)
1546 {
1547     // try to get an API object, which points directly to the
1548     // requested item. If it fail an exception should occur and
1549     // break this operation. Of course returned API object must be
1550     // checked too.
1551     css::uno::Reference< css::container::XNameAccess > xItem;
1552     css::uno::Any aVal = xSet->getByName(sItem);
1553     if (!(aVal >>= xItem) || !xItem.is())
1554     {
1555         throw css::uno::RuntimeException("found corrupted item \"" + sItem + "\".",
1556                                          css::uno::Reference< css::uno::XInterface >());
1557     }
1558 
1559     // set too. Of course it's already used as key into the e.g. outside
1560     // used hash map... but some of our API methods provide
1561     // this property set as result only. But the user of this CacheItem
1562     // should know, which value the key names has :-) IT'S IMPORTANT!
1563     CacheItem aItem;
1564     aItem[PROPNAME_NAME] <<= sItem;
1565     switch(eType)
1566     {
1567         case E_TYPE :
1568         {
1569             assert(eOption >= 0 && eOption <= E_READ_ALL);
1570             css::uno::Sequence< OUString > &rNames = m_aTypeProps[eOption];
1571 
1572             // read standard properties of a filter
1573             if (rNames.hasElements())
1574             {
1575                 css::uno::Reference< css::beans::XMultiPropertySet >
1576                     xPropSet( xItem, css::uno::UNO_QUERY_THROW);
1577                 css::uno::Sequence< css::uno::Any > aValues = xPropSet->getPropertyValues(rNames);
1578 
1579                 for (sal_Int32 i = 0; i < aValues.getLength(); i++)
1580                     aItem[rNames[i]] = aValues[i];
1581             }
1582 
1583             // read optional properties of a type
1584             // no else here! Is an additional switch ...
1585             if (eOption == E_READ_UPDATE || eOption == E_READ_ALL)
1586                 impl_readPatchUINames(xItem, aItem);
1587         }
1588         break;
1589 
1590 
1591         case E_FILTER :
1592         {
1593             assert(eOption >= 0 && eOption <= E_READ_ALL);
1594             css::uno::Sequence< OUString > &rNames = m_aStandardProps[eOption];
1595 
1596             // read standard properties of a filter
1597             if (rNames.hasElements())
1598             {
1599                 css::uno::Reference< css::beans::XMultiPropertySet >
1600                     xPropSet( xItem, css::uno::UNO_QUERY_THROW);
1601                 css::uno::Sequence< css::uno::Any > aValues = xPropSet->getPropertyValues(rNames);
1602 
1603                 for (sal_Int32 i = 0; i < rNames.getLength(); i++)
1604                 {
1605                     OUString &rPropName = rNames[i];
1606                     if (i != rNames.getLength() - 1 || rPropName != PROPNAME_FLAGS)
1607                         aItem[rPropName] = aValues[i];
1608                     else
1609                     {
1610                         assert(rPropName == PROPNAME_FLAGS);
1611                         // special handling for flags! Convert it from a list of names to its
1612                         // int representation ...
1613                         css::uno::Sequence< OUString > lFlagNames;
1614                         if (aValues[i] >>= lFlagNames)
1615                             aItem[rPropName] <<= static_cast<sal_Int32>(FilterCache::impl_convertFlagNames2FlagField(lFlagNames));
1616                     }
1617                 }
1618             }
1619 //TODO remove it if moving of filter uinames to type uinames
1620 //       will be finished really
1621 #ifdef AS_ENABLE_FILTER_UINAMES
1622             if (eOption == E_READ_UPDATE || eOption == E_READ_ALL)
1623                 impl_readPatchUINames(xItem, aItem);
1624 #endif // AS_ENABLE_FILTER_UINAMES
1625         }
1626         break;
1627 
1628         case E_FRAMELOADER :
1629         case E_CONTENTHANDLER :
1630             aItem[PROPNAME_TYPES] = xItem->getByName(PROPNAME_TYPES);
1631             break;
1632         default: break;
1633     }
1634 
1635     return aItem;
1636 }
1637 
1638 CacheItemList::iterator FilterCache::impl_loadItemOnDemand(      EItemType        eType,
1639                                                            const OUString& sItem)
1640 {
1641     CacheItemList*                              pList   = nullptr;
1642     css::uno::Reference< css::uno::XInterface > xConfig    ;
1643     OUString                             sSet       ;
1644 
1645     switch(eType)
1646     {
1647         case E_TYPE :
1648         {
1649             pList   = &m_lTypes;
1650             xConfig = impl_openConfig(E_PROVIDER_TYPES);
1651             sSet    = CFGSET_TYPES;
1652         }
1653         break;
1654 
1655         case E_FILTER :
1656         {
1657             pList   = &m_lFilters;
1658             xConfig = impl_openConfig(E_PROVIDER_FILTERS);
1659             sSet    = CFGSET_FILTERS;
1660         }
1661         break;
1662 
1663         case E_FRAMELOADER :
1664         {
1665             pList   = &m_lFrameLoaders;
1666             xConfig = impl_openConfig(E_PROVIDER_OTHERS);
1667             sSet    = CFGSET_FRAMELOADERS;
1668         }
1669         break;
1670 
1671         case E_CONTENTHANDLER :
1672         {
1673             pList   = &m_lContentHandlers;
1674             xConfig = impl_openConfig(E_PROVIDER_OTHERS);
1675             sSet    = CFGSET_CONTENTHANDLERS;
1676         }
1677         break;
1678     }
1679 
1680     if (!pList)
1681         throw css::container::NoSuchElementException();
1682 
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;
1686 
1687     CacheItemList::iterator pItemInCache  = pList->find(sItem);
1688     bool                bItemInConfig = xSet->hasByName(sItem);
1689 
1690     if (bItemInConfig)
1691     {
1692         (*pList)[sItem] = impl_loadItem(xSet, eType, sItem, E_READ_ALL);
1693     }
1694     else
1695     {
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();
1704     }
1705 
1706     return pList->find(sItem);
1707 }
1708 
1709 void FilterCache::impl_saveItem(const css::uno::Reference< css::container::XNameReplace >& xItem,
1710                                       EItemType                                            eType,
1711                                 const CacheItem & aItem)
1712 {
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);
1717 
1718     CacheItem::const_iterator pIt;
1719     switch(eType)
1720     {
1721 
1722         case E_TYPE :
1723         {
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);
1745 
1746             css::uno::Reference< css::container::XNameReplace > xUIName;
1747             xItem->getByName(PROPNAME_UINAME) >>= xUIName;
1748             impl_savePatchUINames(xUIName, copiedItem);
1749         }
1750         break;
1751 
1752 
1753         case E_FILTER :
1754         {
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);
1776 
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())
1781             {
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);
1787             }
1788 
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
1796         }
1797         break;
1798 
1799 
1800         case E_FRAMELOADER :
1801         case E_CONTENTHANDLER :
1802         {
1803             pIt = copiedItem.find(PROPNAME_TYPES);
1804             if (pIt != copiedItem.end())
1805                 xItem->replaceByName(PROPNAME_TYPES, pIt->second);
1806         }
1807         break;
1808         default: break;
1809     }
1810 }
1811 
1812 /*-----------------------------------------------
1813     static! => no locks necessary
1814 -----------------------------------------------*/
1815 css::uno::Sequence< OUString > FilterCache::impl_convertFlagField2FlagNames(SfxFilterFlags nFlags)
1816 {
1817     std::vector<OUString> lFlagNames;
1818 
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);
1842 
1843     return comphelper::containerToSequence(lFlagNames);
1844 }
1845 
1846 /*-----------------------------------------------
1847     static! => no locks necessary
1848 -----------------------------------------------*/
1849 SfxFilterFlags FilterCache::impl_convertFlagNames2FlagField(const css::uno::Sequence< OUString >& lNames)
1850 {
1851     SfxFilterFlags nField = SfxFilterFlags::NONE;
1852 
1853     const OUString* pNames = lNames.getConstArray();
1854     sal_Int32       c      = lNames.getLength();
1855     for (sal_Int32 i=0; i<c; ++i)
1856     {
1857         if (pNames[i] == FLAGNAME_3RDPARTYFILTER)
1858         {
1859             nField |= SfxFilterFlags::STARONEFILTER;
1860             continue;
1861         }
1862         if (pNames[i] == FLAGNAME_ALIEN)
1863         {
1864             nField |= SfxFilterFlags::ALIEN;
1865             continue;
1866         }
1867         if (pNames[i] == FLAGNAME_CONSULTSERVICE)
1868         {
1869             nField |= SfxFilterFlags::CONSULTSERVICE;
1870             continue;
1871         }
1872         if (pNames[i] == FLAGNAME_DEFAULT)
1873         {
1874             nField |= SfxFilterFlags::DEFAULT;
1875             continue;
1876         }
1877         if (pNames[i] == FLAGNAME_ENCRYPTION)
1878         {
1879             nField |= SfxFilterFlags::ENCRYPTION;
1880             continue;
1881         }
1882         if (pNames[i] == FLAGNAME_EXOTIC)
1883         {
1884             nField |= SfxFilterFlags::EXOTIC;
1885             continue;
1886         }
1887         if (pNames[i] == FLAGNAME_EXPORT)
1888         {
1889             nField |= SfxFilterFlags::EXPORT;
1890             continue;
1891         }
1892         if (pNames[i] == FLAGNAME_GPGENCRYPTION)
1893         {
1894             nField |= SfxFilterFlags::GPGENCRYPTION;
1895             continue;
1896         }
1897         if (pNames[i] == FLAGNAME_IMPORT)
1898         {
1899             nField |= SfxFilterFlags::IMPORT;
1900             continue;
1901         }
1902         if (pNames[i] == FLAGNAME_INTERNAL)
1903         {
1904             nField |= SfxFilterFlags::INTERNAL;
1905             continue;
1906         }
1907         if (pNames[i] == FLAGNAME_NOTINFILEDIALOG)
1908         {
1909             nField |= SfxFilterFlags::NOTINFILEDLG;
1910             continue;
1911         }
1912         if (pNames[i] == FLAGNAME_NOTINSTALLED)
1913         {
1914             nField |= SfxFilterFlags::MUSTINSTALL;
1915             continue;
1916         }
1917         if (pNames[i] == FLAGNAME_OWN)
1918         {
1919             nField |= SfxFilterFlags::OWN;
1920             continue;
1921         }
1922         if (pNames[i] == FLAGNAME_PACKED)
1923         {
1924             nField |= SfxFilterFlags::PACKED;
1925             continue;
1926         }
1927         if (pNames[i] == FLAGNAME_PASSWORDTOMODIFY)
1928         {
1929             nField |= SfxFilterFlags::PASSWORDTOMODIFY;
1930             continue;
1931         }
1932         if (pNames[i] == FLAGNAME_PREFERRED)
1933         {
1934             nField |= SfxFilterFlags::PREFERED;
1935             continue;
1936         }
1937         if (pNames[i] == FLAGNAME_STARTPRESENTATION)
1938         {
1939             nField |= SfxFilterFlags::STARTPRESENTATION;
1940             continue;
1941         }
1942         if (pNames[i] == FLAGNAME_SUPPORTSSIGNING)
1943         {
1944             nField |= SfxFilterFlags::SUPPORTSSIGNING;
1945             continue;
1946         }
1947         if (pNames[i] == FLAGNAME_READONLY)
1948         {
1949             nField |= SfxFilterFlags::OPENREADONLY;
1950             continue;
1951         }
1952         if (pNames[i] == FLAGNAME_SUPPORTSSELECTION)
1953         {
1954             nField |= SfxFilterFlags::SUPPORTSSELECTION;
1955             continue;
1956         }
1957         if (pNames[i] == FLAGNAME_TEMPLATE)
1958         {
1959             nField |= SfxFilterFlags::TEMPLATE;
1960             continue;
1961         }
1962         if (pNames[i] == FLAGNAME_TEMPLATEPATH)
1963         {
1964             nField |= SfxFilterFlags::TEMPLATEPATH;
1965             continue;
1966         }
1967         if (pNames[i] == FLAGNAME_COMBINED)
1968         {
1969             nField |= SfxFilterFlags::COMBINED;
1970             continue;
1971         }
1972     }
1973 
1974     return nField;
1975 }
1976 
1977 
1978 void FilterCache::impl_interpretDataVal4Type(const OUString& sValue,
1979                                                    sal_Int32        nProp ,
1980                                                    CacheItem&       rItem )
1981 {
1982     switch(nProp)
1983     {
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;
1999     }
2000 }
2001 
2002 
2003 void FilterCache::impl_interpretDataVal4Filter(const OUString& sValue,
2004                                                      sal_Int32        nProp ,
2005                                                      CacheItem&       rItem )
2006 {
2007     switch(nProp)
2008     {
2009         // Order
2010         case 0:     {
2011                         sal_Int32 nOrder = sValue.toInt32();
2012                         if (nOrder > 0)
2013                         {
2014                             SAL_WARN( "filter.config", "FilterCache::impl_interpretDataVal4Filter()\nCan not move Order value from filter to type on demand!");
2015                         }
2016                     }
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;
2042     }
2043 }
2044 
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()
2050 {
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...
2054     try
2055     {
2056         css::uno::Reference< css::uno::XInterface > xInt = impl_openConfig(E_PROVIDER_OLD);
2057         css::uno::Reference< css::container::XNameAccess > xCfg(xInt, css::uno::UNO_QUERY_THROW);
2058 
2059         OUString TYPES_SET("Types");
2060 
2061         // May be there is no type set ...
2062         if (xCfg->hasByName(TYPES_SET))
2063         {
2064             css::uno::Reference< css::container::XNameAccess > xSet;
2065             xCfg->getByName(TYPES_SET) >>= xSet;
2066             const css::uno::Sequence< OUString > lItems = xSet->getElementNames();
2067             const OUString*                      pItems = lItems.getConstArray();
2068             for (sal_Int32 i=0; i<lItems.getLength(); ++i)
2069                 m_lTypes[pItems[i]] = impl_readOldItem(xSet, E_TYPE, pItems[i]);
2070         }
2071 
2072         OUString FILTER_SET("Filters");
2073         // May be there is no filter set ...
2074         if (xCfg->hasByName(FILTER_SET))
2075         {
2076             css::uno::Reference< css::container::XNameAccess > xSet;
2077             xCfg->getByName(FILTER_SET) >>= xSet;
2078             const css::uno::Sequence< OUString > lItems = xSet->getElementNames();
2079             const OUString*                      pItems = lItems.getConstArray();
2080             for (sal_Int32 i=0; i<lItems.getLength(); ++i)
2081                 m_lFilters[pItems[i]] = impl_readOldItem(xSet, E_FILTER, pItems[i]);
2082         }
2083     }
2084     /* corrupt filter addon? Because it's external (optional) code... we can ignore it. Addon won't work then...
2085        but that seems to be acceptable.
2086        see #139088# for further information
2087     */
2088     catch(const css::uno::Exception&)
2089     {
2090     }
2091 }
2092 
2093 CacheItem FilterCache::impl_readOldItem(const css::uno::Reference< css::container::XNameAccess >& xSet ,
2094                                               EItemType                                           eType,
2095                                         const OUString&                                    sItem)
2096 {
2097     css::uno::Reference< css::container::XNameAccess > xItem;
2098     xSet->getByName(sItem) >>= xItem;
2099     if (!xItem.is())
2100         throw css::uno::Exception("Can not read old item.", css::uno::Reference< css::uno::XInterface >());
2101 
2102     CacheItem aItem;
2103     aItem[PROPNAME_NAME] <<= sItem;
2104 
2105     // Installed flag ...
2106     // Isn't used any longer!
2107 
2108     // UIName
2109     impl_readPatchUINames(xItem, aItem);
2110 
2111     // Data
2112     OUString sData;
2113     std::vector<OUString>    lData;
2114     xItem->getByName( "Data" ) >>= sData;
2115     lData = impl_tokenizeString(sData, ',');
2116     if (
2117         (sData.isEmpty()) ||
2118         (lData.empty()    )
2119        )
2120     {
2121         throw css::uno::Exception( "Can not read old item property DATA.", css::uno::Reference< css::uno::XInterface >());
2122     }
2123 
2124     sal_Int32 nProp = 0;
2125     for (auto const& prop : lData)
2126     {
2127         switch(eType)
2128         {
2129             case E_TYPE :
2130                 impl_interpretDataVal4Type(prop, nProp, aItem);
2131                 break;
2132 
2133             case E_FILTER :
2134                 impl_interpretDataVal4Filter(prop, nProp, aItem);
2135                 break;
2136             default: break;
2137         }
2138         ++nProp;
2139     }
2140 
2141     return aItem;
2142 }
2143 
2144 
2145 std::vector<OUString> FilterCache::impl_tokenizeString(const OUString& sData     ,
2146                                                     sal_Unicode      cSeparator)
2147 {
2148     std::vector<OUString> lData  ;
2149     sal_Int32    nToken = 0;
2150     do
2151     {
2152         OUString sToken = sData.getToken(0, cSeparator, nToken);
2153         lData.push_back(sToken);
2154     }
2155     while(nToken >= 0);
2156     return lData;
2157 }
2158 
2159 #if OSL_DEBUG_LEVEL > 0
2160 
2161 
2162 OUString FilterCache::impl_searchFrameLoaderForType(const OUString& sType) const
2163 {
2164     for (auto const& frameLoader : m_lFrameLoaders)
2165     {
2166         const OUString& sItem = frameLoader.first;
2167         ::comphelper::SequenceAsHashMap lProps(frameLoader.second);
2168         std::vector<OUString>           lTypes(
2169                 comphelper::sequenceToContainer< std::vector<OUString> >(lProps[PROPNAME_TYPES].get<css::uno::Sequence<OUString> >()));
2170 
2171         if (::std::find(lTypes.begin(), lTypes.end(), sType) != lTypes.end())
2172             return sItem;
2173     }
2174 
2175     return OUString();
2176 }
2177 
2178 
2179 OUString FilterCache::impl_searchContentHandlerForType(const OUString& sType) const
2180 {
2181     for (auto const& contentHandler : m_lContentHandlers)
2182     {
2183         const OUString& sItem = contentHandler.first;
2184         ::comphelper::SequenceAsHashMap lProps(contentHandler.second);
2185         std::vector<OUString>           lTypes(
2186                 comphelper::sequenceToContainer< std::vector<OUString> >( lProps[PROPNAME_TYPES].get<css::uno::Sequence<OUString> >() ));
2187         if (::std::find(lTypes.begin(), lTypes.end(), sType) != lTypes.end())
2188             return sItem;
2189     }
2190 
2191     return OUString();
2192 }
2193 #endif
2194 
2195 
2196 bool FilterCache::impl_isModuleInstalled(const OUString& sModule)
2197 {
2198     css::uno::Reference< css::container::XNameAccess > xCfg;
2199 
2200     // SAFE ->
2201     {
2202         osl::MutexGuard aLock(m_aLock);
2203         if (!m_xModuleCfg.is())
2204         {
2205             m_xModuleCfg = officecfg::Setup::Office::Factories::get();
2206         }
2207 
2208         xCfg = m_xModuleCfg;
2209     }
2210     // <- SAFE
2211 
2212     if (xCfg.is())
2213         return xCfg->hasByName(sModule);
2214 
2215     return false;
2216 }
2217 
2218     } // namespace config
2219 } // namespace filter
2220 
2221 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2222