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
