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 #include <accelerators/presethandler.hxx>
21 
22 #include <classes/fwkresid.hxx>
23 
24 #include <strings.hrc>
25 
26 #include <com/sun/star/configuration/CorruptedUIConfigurationException.hpp>
27 #include <com/sun/star/container/XNameAccess.hpp>
28 #include <com/sun/star/embed/ElementModes.hpp>
29 #include <com/sun/star/embed/FileSystemStorageFactory.hpp>
30 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
31 #include <com/sun/star/util/thePathSettings.hpp>
32 
33 #include <utility>
34 #include <vcl/svapp.hxx>
35 #include <cppuhelper/exc_hlp.hxx>
36 #include <rtl/ustrbuf.hxx>
37 #include <osl/diagnose.h>
38 #include <i18nlangtag/languagetag.hxx>
39 
40 const ::sal_Int32 ID_CORRUPT_UICONFIG_SHARE   = 1;
41 const ::sal_Int32 ID_CORRUPT_UICONFIG_USER    = 2;
42 const ::sal_Int32 ID_CORRUPT_UICONFIG_GENERAL = 3;
43 
44 namespace framework
45 {
46 
47 namespace {
48 
49 /** @short  because a concurrent access to the same storage from different implementations
50             isn't supported, we have to share it with others.
51 
52     @descr  This struct is allegedly shared and must be used within a
53             synchronized section. But it isn't.
54  */
55 struct TSharedStorages final
56 {
57         StorageHolder m_lStoragesShare;
58         StorageHolder m_lStoragesUser;
59 
TSharedStoragesframework::__anonee0c15eb0111::TSharedStorages60         TSharedStorages()
61         {};
62 };
63 
64 /** @short  provides access to the:
65             a) shared root storages
66             b) shared "inbetween" storages
67             of the share and user layer. */
SharedStorages()68 TSharedStorages& SharedStorages()
69 {
70     static TSharedStorages theStorages;
71     return theStorages;
72 }
73 
74 }
75 
PresetHandler(css::uno::Reference<css::uno::XComponentContext> xContext)76 PresetHandler::PresetHandler(css::uno::Reference< css::uno::XComponentContext > xContext)
77     : m_xContext(std::move(xContext))
78     , m_eConfigType(E_GLOBAL)
79 {
80 }
81 
PresetHandler(const PresetHandler & rCopy)82 PresetHandler::PresetHandler(const PresetHandler& rCopy)
83 {
84     m_xContext              = rCopy.m_xContext;
85     m_eConfigType           = rCopy.m_eConfigType;
86     m_xWorkingStorageShare  = rCopy.m_xWorkingStorageShare;
87     m_xWorkingStorageNoLang = rCopy.m_xWorkingStorageNoLang;
88     m_xWorkingStorageUser   = rCopy.m_xWorkingStorageUser;
89     m_lDocumentStorages     = rCopy.m_lDocumentStorages;
90     m_sRelPathShare         = rCopy.m_sRelPathShare;
91     m_sRelPathUser          = rCopy.m_sRelPathUser;
92 }
93 
~PresetHandler()94 PresetHandler::~PresetHandler()
95 {
96     m_xWorkingStorageShare.clear();
97     m_xWorkingStorageNoLang.clear();
98     m_xWorkingStorageUser.clear();
99 
100     /* #i46497#
101         Don't call forgetCachedStorages() here for shared storages.
102         Because we opened different sub storages by using openPath().
103         And every already open path was reused and referenced (means it's
104         ref count was increased!)
105         So now we have to release our ref counts to these shared storages
106         only ... and not to free all used storages.
107         Otherwise we will disconnect all other open configuration access
108         objects which base on these storages.
109      */
110     auto & sharedStorages = SharedStorages();
111     sharedStorages.m_lStoragesShare.closePath(m_sRelPathShare);
112     sharedStorages.m_lStoragesUser.closePath (m_sRelPathUser );
113 
114     /* On the other side closePath() is not needed for our special handled
115        document storage. Because it's not shared with others ... so we can
116        free it.
117      */
118     m_lDocumentStorages.forgetCachedStorages();
119 }
120 
forgetCachedStorages()121 void PresetHandler::forgetCachedStorages()
122 {
123     SolarMutexGuard g;
124 
125     if (m_eConfigType == E_DOCUMENT)
126     {
127         m_xWorkingStorageShare.clear();
128         m_xWorkingStorageNoLang.clear();
129         m_xWorkingStorageUser.clear();
130     }
131 
132     m_lDocumentStorages.forgetCachedStorages();
133 }
134 
135 namespace {
136 
lcl_getLocalizedMessage(::sal_Int32 nID)137 OUString lcl_getLocalizedMessage(::sal_Int32 nID)
138 {
139     OUString sMessage(u"Unknown error."_ustr);
140 
141     switch(nID)
142     {
143         case ID_CORRUPT_UICONFIG_SHARE :
144                 sMessage = FwkResId(STR_CORRUPT_UICFG_SHARE);
145 
146                 break;
147 
148         case ID_CORRUPT_UICONFIG_USER :
149                 sMessage = FwkResId(STR_CORRUPT_UICFG_USER);
150                 break;
151 
152         case ID_CORRUPT_UICONFIG_GENERAL :
153                 sMessage = FwkResId(STR_CORRUPT_UICFG_GENERAL);
154                 break;
155     }
156 
157     return sMessage;
158 }
159 
lcl_throwCorruptedUIConfigurationException(css::uno::Any const & exception,sal_Int32 id)160 void lcl_throwCorruptedUIConfigurationException(
161     css::uno::Any const & exception, sal_Int32 id)
162 {
163     css::uno::Exception e;
164     bool ok = (exception >>= e);
165     OSL_ASSERT(ok);
166     throw css::configuration::CorruptedUIConfigurationException(
167         lcl_getLocalizedMessage(id),
168         css::uno::Reference< css::uno::XInterface >(),
169         exception.getValueTypeName() + ": \"" + e.Message + "\"");
170 }
171 
172 }
173 
getOrCreateRootStorageShare()174 css::uno::Reference< css::embed::XStorage > PresetHandler::getOrCreateRootStorageShare()
175 {
176     auto & sharedStorages = SharedStorages();
177     css::uno::Reference< css::embed::XStorage > xRoot = sharedStorages.m_lStoragesShare.getRootStorage();
178     if (xRoot.is())
179         return xRoot;
180 
181     css::uno::Reference< css::uno::XComponentContext > xContext;
182     {
183         SolarMutexGuard g;
184         xContext = m_xContext;
185     }
186 
187     css::uno::Reference< css::util::XPathSettings > xPathSettings =
188         css::util::thePathSettings::get( xContext );
189 
190     OUString sShareLayer = xPathSettings->getBasePathShareLayer();
191 
192     // "UIConfig" is a "multi path" ... use first part only here!
193     sal_Int32 nPos = sShareLayer.indexOf(';');
194     if (nPos > 0)
195         sShareLayer = sShareLayer.copy(0, nPos);
196 
197     // Note: May be an user uses URLs without a final slash! Check it ...
198     nPos = sShareLayer.lastIndexOf('/');
199     if (nPos != sShareLayer.getLength()-1)
200         sShareLayer += "/";
201 
202     sShareLayer += "soffice.cfg";
203     /*
204     // TODO remove me!
205     // Attention: This is temp. workaround ... We create a temp. storage file
206     // based of a system directory. This must be used so, till the storage implementation
207     // can work on directories too.
208     */
209     css::uno::Sequence< css::uno::Any > lArgs{
210         css::uno::Any(sShareLayer),
211         css::uno::Any(css::embed::ElementModes::READ | css::embed::ElementModes::NOCREATE)
212     };
213 
214     css::uno::Reference< css::lang::XSingleServiceFactory > xStorageFactory = css::embed::FileSystemStorageFactory::create( xContext );
215     css::uno::Reference< css::embed::XStorage >             xStorage;
216 
217     try
218     {
219         xStorage.set(xStorageFactory->createInstanceWithArguments(lArgs), css::uno::UNO_QUERY_THROW);
220     }
221     catch(const css::uno::Exception&)
222     {
223         css::uno::Any ex(cppu::getCaughtException());
224         lcl_throwCorruptedUIConfigurationException(
225             ex, ID_CORRUPT_UICONFIG_SHARE);
226     }
227 
228     sharedStorages.m_lStoragesShare.setRootStorage(xStorage);
229 
230     return xStorage;
231 }
232 
getOrCreateRootStorageUser()233 css::uno::Reference< css::embed::XStorage > PresetHandler::getOrCreateRootStorageUser()
234 {
235     auto & sharedStorages = SharedStorages();
236     css::uno::Reference< css::embed::XStorage > xRoot = sharedStorages.m_lStoragesUser.getRootStorage();
237     if (xRoot.is())
238         return xRoot;
239 
240     css::uno::Reference< css::uno::XComponentContext > xContext;
241     {
242         SolarMutexGuard g;
243         xContext = m_xContext;
244     }
245 
246     css::uno::Reference< css::util::XPathSettings > xPathSettings =
247         css::util::thePathSettings::get( xContext );
248 
249     OUString sUserLayer = xPathSettings->getBasePathUserLayer();
250 
251     // Note: May be an user uses URLs without a final slash! Check it ...
252     sal_Int32 nPos = sUserLayer.lastIndexOf('/');
253     if (nPos != sUserLayer.getLength()-1)
254         sUserLayer += "/";
255 
256     sUserLayer  += "soffice.cfg"; // storage file
257 
258     css::uno::Sequence< css::uno::Any > lArgs{ css::uno::Any(sUserLayer),
259                                                css::uno::Any(css::embed::ElementModes::READWRITE) };
260 
261     css::uno::Reference< css::lang::XSingleServiceFactory > xStorageFactory = css::embed::FileSystemStorageFactory::create( xContext );
262     css::uno::Reference< css::embed::XStorage >             xStorage;
263 
264     try
265     {
266         xStorage.set(xStorageFactory->createInstanceWithArguments(lArgs), css::uno::UNO_QUERY_THROW);
267     }
268     catch(const css::uno::Exception&)
269     {
270         css::uno::Any ex(cppu::getCaughtException());
271         lcl_throwCorruptedUIConfigurationException(
272             ex, ID_CORRUPT_UICONFIG_USER);
273     }
274 
275     sharedStorages.m_lStoragesUser.setRootStorage(xStorage);
276 
277     return xStorage;
278 }
279 
getWorkingStorageUser() const280 css::uno::Reference< css::embed::XStorage > PresetHandler::getWorkingStorageUser() const
281 {
282     SolarMutexGuard g;
283     return m_xWorkingStorageUser;
284 }
285 
getParentStorageShare()286 css::uno::Reference< css::embed::XStorage > PresetHandler::getParentStorageShare()
287 {
288     css::uno::Reference< css::embed::XStorage > xWorking;
289     {
290         SolarMutexGuard g;
291         xWorking = m_xWorkingStorageShare;
292     }
293 
294     return SharedStorages().m_lStoragesShare.getParentStorage(xWorking);
295 }
296 
getParentStorageUser()297 css::uno::Reference< css::embed::XStorage > PresetHandler::getParentStorageUser()
298 {
299     css::uno::Reference< css::embed::XStorage > xWorking;
300     {
301         SolarMutexGuard g;
302         xWorking = m_xWorkingStorageUser;
303     }
304 
305     return SharedStorages().m_lStoragesUser.getParentStorage(xWorking);
306 }
307 
connectToResource(PresetHandler::EConfigType eConfigType,std::u16string_view sResource,std::u16string_view sModule,const css::uno::Reference<css::embed::XStorage> & xDocumentRoot,const LanguageTag & rLanguageTag)308 void PresetHandler::connectToResource(      PresetHandler::EConfigType                   eConfigType  ,
309                                       std::u16string_view                             sResource    ,
310                                       std::u16string_view                             sModule      ,
311                                       const css::uno::Reference< css::embed::XStorage >& xDocumentRoot,
312                                       const LanguageTag&                                 rLanguageTag )
313 {
314     // TODO free all current open storages!
315 
316     {
317         SolarMutexGuard g;
318         m_eConfigType   = eConfigType;
319     }
320 
321     css::uno::Reference< css::embed::XStorage > xShare;
322     css::uno::Reference< css::embed::XStorage > xNoLang;
323     css::uno::Reference< css::embed::XStorage > xUser;
324 
325     // special case for documents
326     // use outside root storage, if we run in E_DOCUMENT mode!
327     if (eConfigType == E_DOCUMENT)
328     {
329         if (!xDocumentRoot.is())
330             throw css::uno::RuntimeException(
331                     u"There is valid root storage, where the UI configuration can work on."_ustr);
332         m_lDocumentStorages.setRootStorage(xDocumentRoot);
333         xShare = xDocumentRoot;
334         xUser  = xDocumentRoot;
335     }
336     else
337     {
338         xShare = getOrCreateRootStorageShare();
339         xUser  = getOrCreateRootStorageUser();
340     }
341 
342     // #...#
343     try
344     {
345 
346     // a) inside share layer we should not create any new structures... We have to use
347     //    existing ones only!
348     // b) inside user layer we can (SOFT mode!) but sometimes we should not (HARD mode!)
349     //    create new empty structures. We should prefer using of any existing structure.
350     sal_Int32 eShareMode = (css::embed::ElementModes::READ      | css::embed::ElementModes::NOCREATE);
351     sal_Int32 eUserMode  = css::embed::ElementModes::READWRITE;
352 
353     OUStringBuffer sRelPathBuf(1024);
354     OUString       sRelPathShare;
355     OUString       sRelPathUser;
356     switch(eConfigType)
357     {
358         case E_GLOBAL :
359         {
360             sRelPathShare = OUString::Concat("global/") + sResource;
361             sRelPathUser  = sRelPathShare;
362 
363             xShare = impl_openPathIgnoringErrors(sRelPathShare, eShareMode, true );
364             xUser  = impl_openPathIgnoringErrors(sRelPathUser , eUserMode , false);
365         }
366         break;
367 
368         case E_MODULES :
369         {
370             sRelPathShare = OUString::Concat("modules/") + sModule + "/" + sResource;
371             sRelPathUser  = sRelPathShare;
372 
373             xShare = impl_openPathIgnoringErrors(sRelPathShare, eShareMode, true );
374             xUser  = impl_openPathIgnoringErrors(sRelPathUser , eUserMode , false);
375         }
376         break;
377 
378         case E_DOCUMENT :
379         {
380             // A document does not have a share layer in real.
381             // It has one layer only, and this one should be opened READ_WRITE.
382             // So we open the user layer here only and set the share layer equals to it .-)
383 
384             sRelPathBuf.append(sResource);
385             sRelPathUser  = sRelPathBuf.makeStringAndClear();
386             sRelPathShare = sRelPathUser;
387 
388             try
389             {
390                 xUser  = m_lDocumentStorages.openPath(sRelPathUser , eUserMode );
391                 xShare = xUser;
392             }
393             catch(const css::uno::RuntimeException&)
394                 { throw; }
395             catch(const css::uno::Exception&)
396                 { xShare.clear(); xUser.clear(); }
397         }
398         break;
399     }
400 
401     // Non-localized global share
402     xNoLang = xShare;
403 
404     if (
405         (rLanguageTag != LanguageTag(LANGUAGE_USER_PRIV_NOTRANSLATE)) && // localized level?
406         (eConfigType != E_DOCUMENT                           )    // no localization in document mode!
407        )
408     {
409         // First try to find the right localized set inside share layer.
410         // Fallbacks are allowed there.
411         OUString         aShareLocale( rLanguageTag.getBcp47());
412         OUString         sLocalizedSharePath(sRelPathShare);
413         bool             bAllowFallbacks    = true;
414         xShare = impl_openLocalizedPathIgnoringErrors(sLocalizedSharePath, eShareMode, true , aShareLocale, bAllowFallbacks);
415 
416         // The try to locate the right sub dir inside user layer ... without using fallbacks!
417         // Normally the corresponding sub dir should be created matching the specified locale.
418         // Because we allow creation of storages inside user layer by default.
419         OUString      aUserLocale( rLanguageTag.getBcp47());
420         OUString      sLocalizedUserPath(sRelPathUser);
421         bAllowFallbacks    = false;
422         xUser = impl_openLocalizedPathIgnoringErrors(sLocalizedUserPath, eUserMode, false, aUserLocale, bAllowFallbacks);
423 
424         sRelPathShare = sLocalizedSharePath;
425         sRelPathUser  = sLocalizedUserPath;
426     }
427 
428     {
429         SolarMutexGuard g;
430         m_xWorkingStorageShare = xShare;
431         m_xWorkingStorageNoLang= xNoLang;
432         m_xWorkingStorageUser  = xUser;
433         m_sRelPathShare        = sRelPathShare;
434         m_sRelPathUser         = sRelPathUser;
435     }
436 
437     }
438     catch(const css::uno::Exception&)
439     {
440         css::uno::Any ex(cppu::getCaughtException());
441         lcl_throwCorruptedUIConfigurationException(
442             ex, ID_CORRUPT_UICONFIG_GENERAL);
443     }
444 }
445 
copyPresetToTarget(std::u16string_view sPreset,std::u16string_view sTarget)446 void PresetHandler::copyPresetToTarget(std::u16string_view sPreset,
447                                        std::u16string_view sTarget)
448 {
449     // don't check our preset list, if element exists
450     // We try to open it and forward all errors to the user!
451 
452     css::uno::Reference< css::embed::XStorage > xWorkingShare;
453     css::uno::Reference< css::embed::XStorage > xWorkingNoLang;
454     css::uno::Reference< css::embed::XStorage > xWorkingUser;
455     {
456         SolarMutexGuard g;
457         xWorkingShare = m_xWorkingStorageShare;
458         xWorkingNoLang= m_xWorkingStorageNoLang;
459         xWorkingUser  = m_xWorkingStorageUser;
460     }
461 
462     // e.g. module without any config data ?!
463     if (
464         (!xWorkingShare.is()) ||
465         (!xWorkingUser.is() )
466        )
467     {
468        return;
469     }
470 
471     OUString sPresetFile = OUString::Concat(sPreset) + ".xml";
472     OUString sTargetFile = OUString::Concat(sTarget) + ".xml";
473 
474     // remove existing elements before you try to copy the preset to that location ...
475     // Otherwise w will get an ElementExistException inside copyElementTo()!
476     css::uno::Reference< css::container::XNameAccess > xCheckingUser(xWorkingUser, css::uno::UNO_QUERY_THROW);
477     if (xCheckingUser->hasByName(sTargetFile))
478         xWorkingUser->removeElement(sTargetFile);
479 
480     xWorkingShare->copyElementTo(sPresetFile, xWorkingUser, sTargetFile);
481 
482     // If our storages work in transacted mode, we have
483     // to commit all changes from bottom to top!
484     commitUserChanges();
485 }
486 
openPreset(std::u16string_view sPreset)487 css::uno::Reference< css::io::XStream > PresetHandler::openPreset(std::u16string_view sPreset)
488 {
489     css::uno::Reference< css::embed::XStorage > xFolder;
490     {
491         SolarMutexGuard g;
492         xFolder = m_xWorkingStorageNoLang;
493     }
494 
495     // e.g. module without any config data ?!
496     if (!xFolder.is())
497        return css::uno::Reference< css::io::XStream >();
498 
499     OUString sFile = OUString::Concat(sPreset) + ".xml";
500 
501     // inform user about errors (use original exceptions!)
502     css::uno::Reference< css::io::XStream > xStream = xFolder->openStreamElement(sFile, css::embed::ElementModes::READ);
503     return xStream;
504 }
505 
openTarget(std::u16string_view sTarget,sal_Int32 const nMode)506 css::uno::Reference< css::io::XStream > PresetHandler::openTarget(
507         std::u16string_view sTarget, sal_Int32 const nMode)
508 {
509     css::uno::Reference< css::embed::XStorage > xFolder;
510     {
511         SolarMutexGuard g;
512         xFolder = m_xWorkingStorageUser;
513     }
514 
515     // e.g. module without any config data ?!
516     if (!xFolder.is())
517        return css::uno::Reference< css::io::XStream >();
518 
519     OUString const sFile(OUString::Concat(sTarget) + ".xml");
520 
521     return xFolder->openStreamElement(sFile, nMode);
522 }
523 
commitUserChanges()524 void PresetHandler::commitUserChanges()
525 {
526     css::uno::Reference< css::embed::XStorage > xWorking;
527     EConfigType                                 eCfgType;
528     {
529         SolarMutexGuard g;
530         xWorking = m_xWorkingStorageUser;
531         eCfgType = m_eConfigType;
532     }
533 
534     // e.g. module without any config data ?!
535     if (!xWorking.is())
536        return;
537 
538     OUString sPath;
539 
540     switch(eCfgType)
541     {
542         case E_GLOBAL :
543         case E_MODULES :
544         {
545             auto & sharedStorages = SharedStorages();
546             sPath = sharedStorages.m_lStoragesUser.getPathOfStorage(xWorking);
547             sharedStorages.m_lStoragesUser.commitPath(sPath);
548             sharedStorages.m_lStoragesUser.notifyPath(sPath);
549         }
550         break;
551 
552         case E_DOCUMENT :
553         {
554             sPath = m_lDocumentStorages.getPathOfStorage(xWorking);
555             m_lDocumentStorages.commitPath(sPath);
556             m_lDocumentStorages.notifyPath(sPath);
557         }
558         break;
559     }
560 }
561 
addStorageListener(XMLBasedAcceleratorConfiguration * pListener)562 void PresetHandler::addStorageListener(XMLBasedAcceleratorConfiguration* pListener)
563 {
564     OUString sRelPath;
565     EConfigType eCfgType;
566     {
567         SolarMutexGuard g;
568         sRelPath = m_sRelPathUser; // use user path ... because we don't work directly on the share layer!
569         eCfgType = m_eConfigType;
570     }
571 
572     if (sRelPath.isEmpty())
573         return;
574 
575     switch(eCfgType)
576     {
577         case E_GLOBAL :
578         case E_MODULES :
579         {
580             SharedStorages().m_lStoragesUser.addStorageListener(pListener, sRelPath);
581         }
582         break;
583 
584         case E_DOCUMENT :
585         {
586             m_lDocumentStorages.addStorageListener(pListener, sRelPath);
587         }
588         break;
589     }
590 }
591 
removeStorageListener(XMLBasedAcceleratorConfiguration * pListener)592 void PresetHandler::removeStorageListener(XMLBasedAcceleratorConfiguration* pListener)
593 {
594     OUString sRelPath;
595     EConfigType eCfgType;
596     {
597         SolarMutexGuard g;
598         sRelPath = m_sRelPathUser; // use user path ... because we don't work directly on the share layer!
599         eCfgType = m_eConfigType;
600     }
601 
602     if (sRelPath.isEmpty())
603         return;
604 
605     switch(eCfgType)
606     {
607         case E_GLOBAL :
608         case E_MODULES :
609         {
610             SharedStorages().m_lStoragesUser.removeStorageListener(pListener, sRelPath);
611         }
612         break;
613 
614         case E_DOCUMENT :
615         {
616             m_lDocumentStorages.removeStorageListener(pListener, sRelPath);
617         }
618         break;
619     }
620 }
621 
622 // static
impl_openPathIgnoringErrors(const OUString & sPath,sal_Int32 eMode,bool bShare)623 css::uno::Reference< css::embed::XStorage > PresetHandler::impl_openPathIgnoringErrors(const OUString& sPath ,
624                                                                                              sal_Int32        eMode ,
625                                                                                              bool         bShare)
626 {
627     css::uno::Reference< css::embed::XStorage > xPath;
628     try
629     {
630         if (bShare)
631             xPath = SharedStorages().m_lStoragesShare.openPath(sPath, eMode);
632         else
633             xPath = SharedStorages().m_lStoragesUser.openPath(sPath, eMode);
634     }
635     catch(const css::uno::RuntimeException&)
636         { throw; }
637     catch(const css::uno::Exception&)
638         { xPath.clear(); }
639     return xPath;
640 }
641 
642 // static
impl_findMatchingLocalizedValue(const::std::vector<OUString> & lLocalizedValues,OUString & rLanguageTag,bool bAllowFallbacks)643 ::std::vector< OUString >::const_iterator PresetHandler::impl_findMatchingLocalizedValue(
644         const ::std::vector< OUString >& lLocalizedValues,
645         OUString& rLanguageTag,
646         bool bAllowFallbacks )
647 {
648     ::std::vector< OUString >::const_iterator pFound = lLocalizedValues.end();
649     if (bAllowFallbacks)
650     {
651         pFound = LanguageTag::getFallback(lLocalizedValues, rLanguageTag);
652         // if we found a valid locale ... take it over to our in/out parameter
653         // rLanguageTag
654         if (pFound != lLocalizedValues.end())
655         {
656             rLanguageTag = *pFound;
657         }
658     }
659     else
660     {
661         pFound = std::find(lLocalizedValues.begin(), lLocalizedValues.end(), rLanguageTag);
662     }
663 
664     return pFound;
665 }
666 
667 // static
impl_openLocalizedPathIgnoringErrors(OUString & sPath,sal_Int32 eMode,bool bShare,OUString & rLanguageTag,bool bAllowFallback)668 css::uno::Reference< css::embed::XStorage > PresetHandler::impl_openLocalizedPathIgnoringErrors(
669         OUString&      sPath         ,
670         sal_Int32             eMode         ,
671         bool              bShare        ,
672         OUString&             rLanguageTag  ,
673         bool              bAllowFallback)
674 {
675     css::uno::Reference< css::embed::XStorage >      xPath         = impl_openPathIgnoringErrors(sPath, eMode, bShare);
676     ::std::vector< OUString >                 lSubFolders   = impl_getSubFolderNames(xPath);
677     ::std::vector< OUString >::const_iterator pLocaleFolder = impl_findMatchingLocalizedValue(lSubFolders, rLanguageTag, bAllowFallback);
678 
679     // no fallback ... creation not allowed => no storage
680     if (
681         (pLocaleFolder == lSubFolders.end()                                                ) &&
682         ((eMode & css::embed::ElementModes::NOCREATE) == css::embed::ElementModes::NOCREATE)
683        )
684         return css::uno::Reference< css::embed::XStorage >();
685 
686     // it doesn't matter, if there is a locale fallback or not
687     // If creation of storages is allowed, we do it anyway.
688     // Otherwise we have no acc config at all, which can make other trouble.
689     OUString sLocalizedPath = sPath + "/";
690     if (pLocaleFolder != lSubFolders.end())
691         sLocalizedPath += *pLocaleFolder;
692     else
693         sLocalizedPath += rLanguageTag;
694 
695     css::uno::Reference< css::embed::XStorage > xLocalePath = impl_openPathIgnoringErrors(sLocalizedPath, eMode, bShare);
696 
697     if (xLocalePath.is())
698         sPath = sLocalizedPath;
699     else
700         sPath.clear();
701 
702     return xLocalePath;
703 }
704 
705 // static
impl_getSubFolderNames(const css::uno::Reference<css::embed::XStorage> & xFolder)706 ::std::vector< OUString > PresetHandler::impl_getSubFolderNames(const css::uno::Reference< css::embed::XStorage >& xFolder)
707 {
708     if (!xFolder.is())
709         return ::std::vector< OUString >();
710 
711     ::std::vector< OUString >      lSubFolders;
712     const css::uno::Sequence< OUString > lNames = xFolder->getElementNames();
713     const OUString*                      pNames = lNames.getConstArray();
714     sal_Int32                            c      = lNames.getLength();
715     sal_Int32                            i      = 0;
716 
717     for (i=0; i<c; ++i)
718     {
719         try
720         {
721             if (xFolder->isStorageElement(pNames[i]))
722                 lSubFolders.push_back(pNames[i]);
723         }
724         catch(const css::uno::RuntimeException&)
725             { throw; }
726         catch(const css::uno::Exception&)
727             {}
728     }
729 
730     return lSubFolders;
731 }
732 
733 } // namespace framework
734 
735 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
736