Avoid potential negative array index access to cached text.
[LibreOffice.git] / framework / source / fwi / classes / protocolhandlercache.cxx
blob490e2c91075e09182c4c22ad66e5109cad9a3662
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 /*TODO
21 - change "singleton" behaviour by using new helper ::comhelper::SingletonRef
22 - rename method exist() to existHandlerForURL() or similar one
23 - may it's a good idea to replace struct ProtocolHandler by css::beans::NamedValue type?!
26 #include <classes/protocolhandlercache.hxx>
27 #include <classes/converter.hxx>
29 #include <tools/wldcrd.hxx>
30 #include <unotools/configpaths.hxx>
31 #include <sal/log.hxx>
32 #include <vcl/svapp.hxx>
34 constexpr OUString SETNAME_HANDLER = u"HandlerSet"_ustr; // name of configuration set inside package
36 namespace framework{
38 /**
39 @short overloaded index operator of hash map to support pattern key search
40 @descr All keys inside this hash map are URL pattern which points to a uno
41 implementation name of a protocol handler service which is registered
42 for this pattern. This operator makes it easy to find such registered
43 handler by using a full qualified URL and compare it with all pattern
44 keys.
46 @param sURL
47 the full qualified URL which should match to a registered pattern
49 @return An iterator which points to the found item inside the hash or PatternHash::end()
50 if no pattern match this given <var>sURL</var>.
52 namespace {
54 PatternHash::const_iterator findPatternKey(PatternHash const * hash, const OUString& sURL)
56 return std::find_if(hash->begin(), hash->end(),
57 [&sURL](const PatternHash::value_type& rEntry) {
58 WildCard aPattern(rEntry.first);
59 return aPattern.Matches(sURL);
60 });
65 /**
66 @short initialize static member of class HandlerCache
67 @descr We use a singleton pattern to implement this handler cache.
68 That means it use two static member list to hold all necessary information
69 and a ref count mechanism to create/destroy it on demand.
71 std::optional<HandlerHash> HandlerCache::s_pHandler;
72 std::optional<PatternHash> HandlerCache::s_pPattern;
73 sal_Int32 HandlerCache::m_nRefCount = 0;
74 HandlerCFGAccess* HandlerCache::s_pConfig = nullptr;
76 /**
77 @short ctor of the cache of all registered protocol handler
78 @descr It tries to open the right configuration package automatically
79 and fill the internal structures. After that the cache can be
80 used for read access on this data and perform some search
81 operations on it.
83 HandlerCache::HandlerCache()
85 SolarMutexGuard aGuard;
87 if (m_nRefCount==0)
89 s_pHandler.emplace();
90 s_pPattern.emplace();
91 s_pConfig = new HandlerCFGAccess(PACKAGENAME_PROTOCOLHANDLER);
92 s_pConfig->read(*s_pHandler, *s_pPattern);
93 s_pConfig->setCache(this);
96 ++m_nRefCount;
99 /**
100 @short dtor of the cache
101 @descr It frees all used memory. In further implementations (may if we support write access too)
102 it's a good place to flush changes back to the configuration - but not needed yet.
104 HandlerCache::~HandlerCache()
106 SolarMutexGuard aGuard;
108 if( m_nRefCount==1)
110 s_pConfig->setCache(nullptr);
112 delete s_pConfig;
113 s_pConfig = nullptr;
114 s_pHandler.reset();
115 s_pPattern.reset();
118 --m_nRefCount;
122 @short dtor of the cache
123 @descr It frees all used memory. In further implementations (may if we support write access too)
124 it's a good place to flush changes back to the configuration - but not needed yet.
126 bool HandlerCache::search( const OUString& sURL, ProtocolHandler* pReturn ) const
128 bool bFound = false;
130 SolarMutexGuard aGuard;
132 PatternHash::const_iterator pItem = findPatternKey(s_pPattern ? &*s_pPattern : nullptr, sURL);
133 if (pItem != s_pPattern->end())
135 *pReturn = (*s_pHandler)[pItem->second];
136 bFound = true;
139 return bFound;
143 @short search for a registered handler by using a URL struct
144 @descr We combine necessary parts of this struct to a valid URL string
145 and call our other search method ...
146 It's a helper for outside code.
148 bool HandlerCache::search( const css::util::URL& aURL, ProtocolHandler* pReturn ) const
150 return search( aURL.Complete, pReturn );
153 void HandlerCache::takeOver(HandlerHash aHandler, PatternHash aPattern)
155 SolarMutexGuard aGuard;
157 s_pHandler = std::move(aHandler);
158 s_pPattern = std::move(aPattern);
162 @short dtor of the config access class
163 @descr It opens the configuration package automatically by using base class mechanism.
164 After that "read()" method of this class should be called to use it.
166 @param sPackage
167 specifies the package name of the configuration data which should be used
169 HandlerCFGAccess::HandlerCFGAccess( const OUString& sPackage )
170 : ConfigItem(sPackage)
171 , m_pCache(nullptr)
173 css::uno::Sequence< OUString > lListenPaths { SETNAME_HANDLER };
174 EnableNotification(lListenPaths);
178 @short use base class mechanism to fill given structures
179 @descr User use us as a wrapper between configuration api and his internal structures.
180 He give us some pointer to his member and we fill it.
182 @param rHandlerHash
183 list of protocol handler infos
185 @param rPatternHash
186 reverse map of handler pattern to her uno names
188 void HandlerCFGAccess::read( HandlerHash& rHandlerHash, PatternHash& rPatternHash )
190 // list of all uno implementation names without encoding
191 css::uno::Sequence< OUString > lNames = GetNodeNames( SETNAME_HANDLER, ::utl::ConfigNameFormat::LocalPath );
192 sal_Int32 nSourceCount = lNames.getLength();
193 sal_Int32 nTargetCount = nSourceCount;
194 // list of all full qualified path names of configuration entries
195 css::uno::Sequence< OUString > lFullNames ( nTargetCount );
196 auto lFullNamesRange = asNonConstRange(lFullNames);
197 // expand names to full path names
198 sal_Int32 nSource=0;
199 sal_Int32 nTarget=0;
200 for( nSource=0; nSource<nSourceCount; ++nSource )
202 lFullNamesRange[nTarget] =
203 SETNAME_HANDLER +
204 CFG_PATH_SEPARATOR +
205 lNames[nSource] +
206 CFG_PATH_SEPARATOR
207 PROPERTY_PROTOCOLS;
209 ++nTarget;
212 // get values at all
213 css::uno::Sequence< css::uno::Any > lValues = GetProperties( lFullNames );
214 SAL_WARN_IF( lFullNames.getLength()!=lValues.getLength(), "fwk", "HandlerCFGAccess::read(): Miss some configuration values of handler set!" );
216 // fill structures
217 nSource = 0;
218 for( nTarget=0; nTarget<nTargetCount; ++nTarget )
220 // create it new for every loop to guarantee a real empty object!
221 ProtocolHandler aHandler;
222 aHandler.m_sUNOName = ::utl::extractFirstFromConfigurationPath(lNames[nSource]);
224 // unpack all values of this handler
225 css::uno::Sequence< OUString > lTemp;
226 lValues[nTarget] >>= lTemp;
227 aHandler.m_lProtocols = Converter::convert_seqOUString2OUStringList(lTemp);
229 // register his pattern into the performance search hash
230 for (auto const& item : aHandler.m_lProtocols)
232 rPatternHash[item] = lNames[nSource];
235 // insert the handler info into the normal handler cache
236 rHandlerHash[lNames[nSource]] = aHandler;
237 ++nSource;
241 void HandlerCFGAccess::Notify(const css::uno::Sequence< OUString >& /*lPropertyNames*/)
243 HandlerHash aHandler;
244 PatternHash aPattern;
246 read(aHandler, aPattern);
247 if (m_pCache)
248 m_pCache->takeOver(std::move(aHandler), std::move(aPattern));
251 void HandlerCFGAccess::ImplCommit()
255 } // namespace framework
257 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */