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 <config_folders.h>
21 
22 #include <sal/config.h>
23 #include <sal/log.hxx>
24 
25 #include <deque>
26 #include <string_view>
27 
28 #include <com/sun/star/container/XNameAccess.hpp>
29 #include <com/sun/star/io/XInputStream.hpp>
30 #include <com/sun/star/packages/zip/ZipFileAccess.hpp>
31 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
32 #include <com/sun/star/uno/Exception.hpp>
33 #include <com/sun/star/uno/RuntimeException.hpp>
34 #include <com/sun/star/uno/Sequence.hxx>
35 #include <comphelper/processfactory.hxx>
36 #include <cppuhelper/implbase.hxx>
37 #include <osl/file.hxx>
38 #include <osl/diagnose.h>
39 #include <osl/process.h>
40 #include <rtl/bootstrap.hxx>
41 #include <rtl/uri.hxx>
42 
43 #include <tools/diagnose_ex.h>
44 #include <tools/stream.hxx>
45 #include <tools/urlobj.hxx>
46 #include <implimagetree.hxx>
47 
48 #include <vcl/bitmapex.hxx>
49 #include <vcl/dibtools.hxx>
50 #include <vcl/settings.hxx>
51 #include <vcl/svapp.hxx>
52 #include <vcl/BitmapTools.hxx>
53 #include <IconThemeScanner.hxx>
54 #include <vcl/filter/PngImageReader.hxx>
55 #include <vcl/outdev.hxx>
56 #include <vcl/pngwrite.hxx>
57 
58 #include <bitmap/BitmapLightenFilter.hxx>
59 
60 using namespace css;
61 
convertToDarkTheme()62 bool ImageRequestParameters::convertToDarkTheme()
63 {
64     static bool bIconsForDarkTheme = !!getenv("VCL_ICONS_FOR_DARK_THEME");
65 
66     bool bConvertToDarkTheme = false;
67     if (!(meFlags & ImageLoadFlags::IgnoreDarkTheme))
68         bConvertToDarkTheme = bIconsForDarkTheme;
69 
70     return bConvertToDarkTheme;
71 }
72 
scalePercentage()73 sal_Int32 ImageRequestParameters::scalePercentage()
74 {
75     sal_Int32 aScalePercentage = 100;
76     if (!(meFlags & ImageLoadFlags::IgnoreScalingFactor))
77         aScalePercentage = Application::GetDefaultDevice()->GetDPIScalePercentage();
78     else if (mnScalePercentage > 0)
79         aScalePercentage = mnScalePercentage;
80     return aScalePercentage;
81 }
82 
83 namespace
84 {
85 
convertLcTo32Path(OUString const & rPath)86 OUString convertLcTo32Path(OUString const & rPath)
87 {
88     OUString aResult;
89     if (rPath.lastIndexOf('/') != -1)
90     {
91         sal_Int32 nCopyFrom = rPath.lastIndexOf('/') + 1;
92         OUString sFile = rPath.copy(nCopyFrom);
93         OUString sDir = rPath.copy(0, rPath.lastIndexOf('/'));
94         if (!sFile.isEmpty() && sFile.startsWith("lc_"))
95         {
96             aResult = sDir + "/32/" + sFile.subView(3);
97         }
98     }
99     return aResult;
100 }
101 
createPath(std::u16string_view name,sal_Int32 pos,std::u16string_view locale)102 OUString createPath(std::u16string_view name, sal_Int32 pos, std::u16string_view locale)
103 {
104     return OUString::Concat(name.substr(0, pos + 1)) + locale + name.substr(pos);
105 }
106 
getIconCacheUrl(std::u16string_view sVariant,ImageRequestParameters const & rParameters)107 OUString getIconCacheUrl(std::u16string_view sVariant, ImageRequestParameters const & rParameters)
108 {
109     OUString sUrl = "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/"
110         + rParameters.msStyle + "/" + sVariant + "/" + rParameters.msName;
111     rtl::Bootstrap::expandMacros(sUrl);
112     return sUrl;
113 }
114 
createIconCacheUrl(std::u16string_view sVariant,ImageRequestParameters const & rParameters)115 OUString createIconCacheUrl(
116     std::u16string_view sVariant, ImageRequestParameters const & rParameters)
117 {
118     OUString sUrl(getIconCacheUrl(sVariant, rParameters));
119     OUString sDir = sUrl.copy(0, sUrl.lastIndexOf('/'));
120     osl::Directory::createPath(sDir);
121     return sUrl;
122 }
123 
urlExists(OUString const & sUrl)124 bool urlExists(OUString const & sUrl)
125 {
126     osl::File aFile(sUrl);
127     osl::FileBase::RC eRC = aFile.open(osl_File_OpenFlag_Read);
128     return osl::FileBase::E_None == eRC;
129 }
130 
getNameNoExtension(OUString const & sName)131 OUString getNameNoExtension(OUString const & sName)
132 {
133     sal_Int32 nDotPosition = sName.lastIndexOf('.');
134     return sName.copy(0, nDotPosition);
135 }
136 
wrapStream(uno::Reference<io::XInputStream> const & rInputStream)137 std::shared_ptr<SvMemoryStream> wrapStream(uno::Reference<io::XInputStream> const & rInputStream)
138 {
139     // This could use SvInputStream instead if that did not have a broken
140     // SeekPos implementation for an XInputStream that is not also XSeekable
141     // (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807
142     // l. 593):
143     OSL_ASSERT(rInputStream.is());
144     std::shared_ptr<SvMemoryStream> aMemoryStream(std::make_shared<SvMemoryStream>());
145     for (;;)
146     {
147         const sal_Int32 nSize(2048);
148         uno::Sequence<sal_Int8> aData(nSize);
149         sal_Int32 nRead = rInputStream->readBytes(aData, nSize);
150         aMemoryStream->WriteBytes(aData.getConstArray(), nRead);
151         if (nRead < nSize)
152             break;
153     }
154     aMemoryStream->Seek(0);
155     rInputStream->closeInput();
156     return aMemoryStream;
157 }
158 
loadImageFromStream(std::shared_ptr<SvStream> const & xStream,OUString const & rPath,ImageRequestParameters & rParameters)159 void loadImageFromStream(std::shared_ptr<SvStream> const & xStream, OUString const & rPath, ImageRequestParameters& rParameters)
160 {
161     bool bConvertToDarkTheme = rParameters.convertToDarkTheme();
162     sal_Int32 aScalePercentage = rParameters.scalePercentage();
163 
164     if (rPath.endsWith(".png"))
165     {
166         vcl::PngImageReader aPNGReader(*xStream);
167         aPNGReader.read(rParameters.mrBitmap);
168     }
169     else if (rPath.endsWith(".svg"))
170     {
171         rParameters.mbWriteImageToCache = true; // We always want to cache a SVG image
172         vcl::bitmap::loadFromSvg(*xStream, rPath, rParameters.mrBitmap, aScalePercentage / 100.0);
173 
174         if (bConvertToDarkTheme)
175             BitmapFilter::Filter(rParameters.mrBitmap, BitmapLightenFilter());
176 
177         return;
178     }
179     else
180     {
181         ReadDIBBitmapEx(rParameters.mrBitmap, *xStream);
182     }
183 
184     if (bConvertToDarkTheme)
185     {
186         rParameters.mbWriteImageToCache = true; // Cache the dark variant
187         BitmapFilter::Filter(rParameters.mrBitmap, BitmapLightenFilter());
188     }
189 
190     if (aScalePercentage > 100)
191     {
192         rParameters.mbWriteImageToCache = true; // Cache the scaled variant
193         double aScaleFactor(aScalePercentage / 100.0);
194         // when scaling use the full 24bit RGB values
195         rParameters.mrBitmap.Convert(BmpConversion::N24Bit);
196         rParameters.mrBitmap.Scale(aScaleFactor, aScaleFactor, BmpScaleFlag::Fast);
197     }
198 }
199 
200 } // end anonymous namespace
201 
ImplImageTree()202 ImplImageTree::ImplImageTree()
203 {
204 }
205 
~ImplImageTree()206 ImplImageTree::~ImplImageTree()
207 {
208 }
209 
getPaths(OUString const & name,LanguageTag const & rLanguageTag)210 std::vector<OUString> ImplImageTree::getPaths(OUString const & name, LanguageTag const & rLanguageTag)
211 {
212     std::vector<OUString> sPaths;
213 
214     sal_Int32 pos = name.lastIndexOf('/');
215     if (pos != -1)
216     {
217         for (const OUString& rFallback : rLanguageTag.getFallbackStrings(true))
218         {
219             OUString aFallbackName = getNameNoExtension(getRealImageName(createPath(name, pos, rFallback)));
220             sPaths.emplace_back(aFallbackName + ".png");
221             sPaths.emplace_back(aFallbackName + ".svg");
222         }
223     }
224 
225     OUString aRealName = getNameNoExtension(getRealImageName(name));
226     sPaths.emplace_back(aRealName + ".png");
227     sPaths.emplace_back(aRealName + ".svg");
228 
229     return sPaths;
230 }
231 
getImageUrl(OUString const & rName,OUString const & rStyle,OUString const & rLang)232 OUString ImplImageTree::getImageUrl(OUString const & rName, OUString const & rStyle, OUString const & rLang)
233 {
234     OUString aStyle(rStyle);
235 
236     while (!aStyle.isEmpty())
237     {
238         try
239         {
240             setStyle(aStyle);
241 
242             if (checkPathAccess())
243             {
244                 IconSet& rIconSet = getCurrentIconSet();
245                 const uno::Reference<container::XNameAccess> & rNameAccess = rIconSet.maNameAccess;
246 
247                 LanguageTag aLanguageTag(rLang);
248 
249                 for (const OUString& rPath: getPaths(rName, aLanguageTag))
250                 {
251                     if (rNameAccess->hasByName(rPath))
252                     {
253                         return "vnd.sun.star.zip://"
254                             + rtl::Uri::encode(rIconSet.maURL, rtl_UriCharClassRegName,
255                                                rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8)
256                             + "/" + rPath;
257                     }
258                 }
259             }
260         }
261         catch (const uno::Exception &)
262         {
263             TOOLS_INFO_EXCEPTION("vcl", "");
264         }
265 
266         aStyle = fallbackStyle(aStyle);
267     }
268     return OUString();
269 }
270 
getImageStream(OUString const & rName,OUString const & rStyle,OUString const & rLang)271 std::shared_ptr<SvMemoryStream> ImplImageTree::getImageStream(OUString const & rName, OUString const & rStyle, OUString const & rLang)
272 {
273     OUString aStyle(rStyle);
274 
275     while (!aStyle.isEmpty())
276     {
277         try
278         {
279             setStyle(aStyle);
280 
281             if (checkPathAccess())
282             {
283                 IconSet& rIconSet = getCurrentIconSet();
284                 const uno::Reference<container::XNameAccess>& rNameAccess = rIconSet.maNameAccess;
285 
286                 LanguageTag aLanguageTag(rLang);
287 
288                 for (const OUString& rPath: getPaths(rName, aLanguageTag))
289                 {
290                     if (rNameAccess->hasByName(rPath))
291                     {
292                         uno::Reference<io::XInputStream> aStream;
293                         bool ok = rNameAccess->getByName(rPath) >>= aStream;
294                         assert(ok);
295                         (void)ok; // prevent unused warning in release build
296                         return wrapStream(aStream);
297                     }
298                 }
299             }
300         }
301         catch (const uno::Exception &)
302         {
303             TOOLS_INFO_EXCEPTION("vcl", "");
304         }
305 
306         aStyle = fallbackStyle(aStyle);
307     }
308     return std::shared_ptr<SvMemoryStream>();
309 }
310 
fallbackStyle(std::u16string_view rsStyle)311 OUString ImplImageTree::fallbackStyle(std::u16string_view rsStyle)
312 {
313     OUString sResult;
314 
315     if (rsStyle == u"colibre" || rsStyle == u"helpimg")
316         sResult = "";
317     else if (rsStyle == u"sifr" || rsStyle == u"breeze_dark")
318         sResult = "breeze";
319     else if (rsStyle == u"sifr_dark" )
320         sResult = "breeze_dark";
321     else
322         sResult = "colibre";
323 
324     return sResult;
325 }
326 
loadImage(OUString const & rName,OUString const & rStyle,BitmapEx & rBitmap,bool localized,const ImageLoadFlags eFlags,sal_Int32 nScalePercentage)327 bool ImplImageTree::loadImage(OUString const & rName, OUString const & rStyle, BitmapEx & rBitmap, bool localized,
328                               const ImageLoadFlags eFlags, sal_Int32 nScalePercentage)
329 {
330     OUString aCurrentStyle(rStyle);
331     while (!aCurrentStyle.isEmpty())
332     {
333         try
334         {
335             ImageRequestParameters aParameters(rName, aCurrentStyle, rBitmap, localized, eFlags, nScalePercentage);
336             if (doLoadImage(aParameters))
337                 return true;
338         }
339         catch (uno::RuntimeException &)
340         {}
341 
342         aCurrentStyle = fallbackStyle(aCurrentStyle);
343     }
344     return false;
345 }
346 
347 namespace
348 {
349 
createVariant(ImageRequestParameters & rParameters)350 OUString createVariant(ImageRequestParameters& rParameters)
351 {
352     bool bConvertToDarkTheme = rParameters.convertToDarkTheme();
353     sal_Int32 aScalePercentage = rParameters.scalePercentage();
354 
355     OUString aVariant = OUString::number(aScalePercentage);
356 
357     if (bConvertToDarkTheme)
358         aVariant += "-dark";
359 
360     return aVariant;
361 }
362 
loadDiskCachedVersion(std::u16string_view sVariant,ImageRequestParameters & rParameters)363 bool loadDiskCachedVersion(std::u16string_view sVariant, ImageRequestParameters& rParameters)
364 {
365     OUString sUrl(getIconCacheUrl(sVariant, rParameters));
366     if (!urlExists(sUrl))
367         return false;
368     SvFileStream aFileStream(sUrl, StreamMode::READ);
369     vcl::PngImageReader aPNGReader(aFileStream);
370     aPNGReader.read(rParameters.mrBitmap);
371     return true;
372 }
373 
cacheBitmapToDisk(std::u16string_view sVariant,ImageRequestParameters const & rParameters)374 void cacheBitmapToDisk(std::u16string_view sVariant, ImageRequestParameters const & rParameters)
375 {
376     OUString sUrl(createIconCacheUrl(sVariant, rParameters));
377     vcl::PNGWriter aWriter(rParameters.mrBitmap);
378     try
379     {
380         SvFileStream aStream(sUrl, StreamMode::WRITE);
381         aWriter.Write(aStream);
382         aStream.Close();
383     }
384     catch (...)
385     {}
386 }
387 
388 } // end anonymous namespace
389 
doLoadImage(ImageRequestParameters & rParameters)390 bool ImplImageTree::doLoadImage(ImageRequestParameters& rParameters)
391 {
392     setStyle(rParameters.msStyle);
393 
394     if (iconCacheLookup(rParameters))
395         return true;
396 
397     OUString aVariant = createVariant(rParameters);
398     if (loadDiskCachedVersion(aVariant, rParameters))
399         return true;
400 
401     if (!rParameters.mrBitmap.IsEmpty())
402         rParameters.mrBitmap.SetEmpty();
403 
404     LanguageTag aLanguageTag = Application::GetSettings().GetUILanguageTag();
405 
406     std::vector<OUString> aPaths = getPaths(rParameters.msName, aLanguageTag);
407 
408     bool bFound = false;
409 
410     try
411     {
412         bFound = findImage(aPaths, rParameters);
413     }
414     catch (uno::RuntimeException&)
415     {
416         throw;
417     }
418     catch (const uno::Exception&)
419     {
420         TOOLS_INFO_EXCEPTION("vcl", "ImplImageTree::doLoadImage");
421     }
422 
423     if (bFound)
424     {
425         if (rParameters.mbWriteImageToCache)
426         {
427             cacheBitmapToDisk(aVariant, rParameters);
428         }
429         getIconCache(rParameters)[rParameters.msName] = std::make_pair(rParameters.mbLocalized, rParameters.mrBitmap);
430     }
431 
432     return bFound;
433 }
434 
shutdown()435 void ImplImageTree::shutdown()
436 {
437     maCurrentStyle.clear();
438     maIconSets.clear();
439 }
440 
setStyle(OUString const & style)441 void ImplImageTree::setStyle(OUString const & style)
442 {
443     assert(!style.isEmpty());
444     if (style != maCurrentStyle)
445     {
446         maCurrentStyle = style;
447         createStyle();
448     }
449 }
450 
451 /**
452  * The vcldemo app doesn't set up all the config stuff that the main app does, so we need another
453  * way of finding the cursor images.
454  */
isVclDemo()455 static bool isVclDemo()
456 {
457     static const bool bVclDemoOverride = std::getenv("LIBO_VCL_DEMO") != nullptr;
458     return bVclDemoOverride;
459 }
460 
createStyle()461 void ImplImageTree::createStyle()
462 {
463     if (maIconSets.find(maCurrentStyle) != maIconSets.end())
464         return;
465 
466     OUString sThemeUrl;
467 
468     if (isVclDemo())
469     {
470         if (maCurrentStyle == "default")
471             sThemeUrl = "file://" SRC_ROOT "/icon-themes/colibre-svg";
472         else
473             sThemeUrl = "file://" SRC_ROOT "/icon-themes/" + maCurrentStyle;
474     }
475     else if (maCurrentStyle != "default")
476     {
477         OUString paths = vcl::IconThemeScanner::GetStandardIconThemePath();
478         std::deque<OUString> aPaths;
479         sal_Int32 nIndex = 0;
480         do
481         {
482             aPaths.push_front(paths.getToken(0, ';', nIndex));
483         }
484         while (nIndex >= 0);
485 
486         for (const auto& path : aPaths)
487         {
488             INetURLObject aUrl(path);
489             OSL_ASSERT(!aUrl.HasError());
490 
491             bool ok = aUrl.Append(OUString("images_" + maCurrentStyle), INetURLObject::EncodeMechanism::All);
492             OSL_ASSERT(ok);
493             sThemeUrl = aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE) + ".zip";
494             if (urlExists(sThemeUrl))
495                 break;
496             sThemeUrl.clear();
497         }
498 
499         if (sThemeUrl.isEmpty())
500             return;
501     }
502     else
503     {
504         sThemeUrl += "images";
505         if (!urlExists(sThemeUrl))
506             return;
507     }
508 
509     maIconSets[maCurrentStyle] = IconSet(sThemeUrl);
510 
511     loadImageLinks();
512 }
513 
514 /// Find an icon cache for the right scale factor
getIconCache(const ImageRequestParameters & rParameters)515 ImplImageTree::IconCache &ImplImageTree::getIconCache(const ImageRequestParameters& rParameters)
516 {
517     IconSet &rSet = getCurrentIconSet();
518     auto it = rSet.maScaledIconCaches.find(rParameters.mnScalePercentage);
519     if ( it != rSet.maScaledIconCaches.end() )
520         return *it->second;
521     rSet.maScaledIconCaches[rParameters.mnScalePercentage] = std::make_unique<IconCache>();
522     return *rSet.maScaledIconCaches[rParameters.mnScalePercentage];
523 }
524 
iconCacheLookup(ImageRequestParameters & rParameters)525 bool ImplImageTree::iconCacheLookup(ImageRequestParameters& rParameters)
526 {
527     IconCache& rIconCache = getIconCache(rParameters);
528 
529     IconCache::iterator i(rIconCache.find(getRealImageName(rParameters.msName)));
530     if (i != rIconCache.end() && i->second.first == rParameters.mbLocalized)
531     {
532         rParameters.mrBitmap = i->second.second;
533         return true;
534     }
535 
536     return false;
537 }
538 
findImage(std::vector<OUString> const & rPaths,ImageRequestParameters & rParameters)539 bool ImplImageTree::findImage(std::vector<OUString> const & rPaths, ImageRequestParameters& rParameters)
540 {
541     if (!checkPathAccess())
542         return false;
543 
544     uno::Reference<container::XNameAccess> const & rNameAccess = getCurrentIconSet().maNameAccess;
545 
546     for (OUString const & rPath : rPaths)
547     {
548         if (rNameAccess->hasByName(rPath))
549         {
550             uno::Reference<io::XInputStream> aStream;
551             bool ok = rNameAccess->getByName(rPath) >>= aStream;
552             assert(ok);
553             (void)ok; // prevent unused warning in release build
554 
555             loadImageFromStream(wrapStream(aStream), rPath, rParameters);
556 
557             return true;
558         }
559     }
560     return false;
561 }
562 
loadImageLinks()563 void ImplImageTree::loadImageLinks()
564 {
565     static const OUStringLiteral aLinkFilename(u"links.txt");
566 
567     if (!checkPathAccess())
568         return;
569 
570     const uno::Reference<container::XNameAccess> &rNameAccess = getCurrentIconSet().maNameAccess;
571 
572     if (rNameAccess->hasByName(aLinkFilename))
573     {
574         uno::Reference<io::XInputStream> xStream;
575         bool ok = rNameAccess->getByName(aLinkFilename) >>= xStream;
576         assert(ok);
577         (void)ok; // prevent unused warning in release build
578 
579         parseLinkFile(wrapStream(xStream));
580         return;
581     }
582 }
583 
parseLinkFile(std::shared_ptr<SvStream> const & xStream)584 void ImplImageTree::parseLinkFile(std::shared_ptr<SvStream> const & xStream)
585 {
586     OString aLine;
587     OUString aLink, aOriginal;
588     int nLineNo = 0;
589     while (xStream->ReadLine(aLine))
590     {
591         ++nLineNo;
592         if (aLine.isEmpty())
593             continue;
594 
595         sal_Int32 nIndex = 0;
596         aLink = OStringToOUString(aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8);
597         aOriginal = OStringToOUString(aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8);
598 
599         // skip comments, or incomplete entries
600         if (aLink.isEmpty() || aLink[0] == '#' || aOriginal.isEmpty())
601         {
602             if (aLink.isEmpty() || aOriginal.isEmpty())
603                 SAL_WARN("vcl", "ImplImageTree::parseLinkFile: icon links.txt parse error, incomplete link at line " << nLineNo);
604             continue;
605         }
606 
607         getCurrentIconSet().maLinkHash[aLink] = aOriginal;
608 
609         OUString aOriginal32 = convertLcTo32Path(aOriginal);
610         OUString aLink32 = convertLcTo32Path(aLink);
611 
612         if (!aOriginal32.isEmpty() && !aLink32.isEmpty())
613             getCurrentIconSet().maLinkHash[aLink32] = aOriginal32;
614     }
615 }
616 
getRealImageName(OUString const & rIconName)617 OUString const & ImplImageTree::getRealImageName(OUString const & rIconName)
618 {
619     IconLinkHash & rLinkHash = maIconSets[maCurrentStyle].maLinkHash;
620 
621     OUString sNameWithNoExtension = getNameNoExtension(rIconName);
622 
623     // PNG is priority
624     auto it = rLinkHash.find(sNameWithNoExtension + ".png");
625     if (it != rLinkHash.end())
626         return it->second;
627 
628     // also check SVG name
629     it = rLinkHash.find(sNameWithNoExtension + ".svg");
630     if (it != rLinkHash.end())
631         return it->second;
632 
633     // neither was found so just return the original name
634     return rIconName;
635 }
636 
637 namespace {
638 
639 class FolderFileAccess : public ::cppu::WeakImplHelper<css::container::XNameAccess>
640 {
641 public:
642     uno::Reference< uno::XComponentContext > mxContext;
643     OUString maURL;
FolderFileAccess(uno::Reference<uno::XComponentContext> const & context,OUString const & url)644     FolderFileAccess(uno::Reference< uno::XComponentContext > const & context, OUString const & url)
645         : mxContext(context), maURL(url) {}
646     // XElementAccess
getElementType()647     virtual css::uno::Type SAL_CALL getElementType() override { return cppu::UnoType<io::XInputStream>::get(); }
hasElements()648     virtual sal_Bool SAL_CALL hasElements() override { return true; }
649     // XNameAccess
getByName(const OUString & aName)650     virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override
651     {
652         uno::Reference< io::XInputStream > xInputStream = ucb::SimpleFileAccess::create(mxContext)->openFileRead( maURL + "/" + aName );
653         return css::uno::Any(xInputStream);
654     }
getElementNames()655     virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override
656     {
657         return {};
658     }
hasByName(const OUString & aName)659     virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
660     {
661         osl::File aBaseFile(maURL + "/" + aName);
662         return osl::File::E_None == aBaseFile.open(osl_File_OpenFlag_Read);
663     }
664 };
665 
666 }
667 
checkPathAccess()668 bool ImplImageTree::checkPathAccess()
669 {
670     IconSet& rIconSet = getCurrentIconSet();
671     uno::Reference<container::XNameAccess> & rNameAccess = rIconSet.maNameAccess;
672     if (rNameAccess.is())
673         return true;
674 
675     try
676     {
677         if (isVclDemo())
678             rNameAccess = new FolderFileAccess(comphelper::getProcessComponentContext(), rIconSet.maURL);
679         else
680             rNameAccess = packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), rIconSet.maURL);
681     }
682     catch (const uno::RuntimeException &)
683     {
684         throw;
685     }
686     catch (const uno::Exception &)
687     {
688         TOOLS_INFO_EXCEPTION("vcl", "ImplImageTree::zip file location " << rIconSet.maURL);
689         return false;
690     }
691     return rNameAccess.is();
692 }
693 
getNameAccess()694 uno::Reference<container::XNameAccess> const & ImplImageTree::getNameAccess()
695 {
696     (void)checkPathAccess();
697     return getCurrentIconSet().maNameAccess;
698 }
699 
700 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
701