cid#1636561 Dereference after null check
[LibreOffice.git] / unotools / source / config / confignode.cxx
bloba80e3c26c5af483e4e6bd548d1bdb7f6d5ff4e37
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 #include <unotools/confignode.hxx>
21 #include <unotools/configpaths.hxx>
22 #include <comphelper/diagnose_ex.hxx>
23 #include <osl/diagnose.h>
24 #include <sal/log.hxx>
25 #include <com/sun/star/configuration/theDefaultProvider.hpp>
26 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
27 #include <com/sun/star/lang/XComponent.hpp>
28 #include <com/sun/star/util/XChangesBatch.hpp>
29 #include <com/sun/star/util/XStringEscape.hpp>
30 #include <com/sun/star/lang/XServiceInfo.hpp>
31 #include <com/sun/star/container/XNamed.hpp>
32 #include <com/sun/star/container/XNameContainer.hpp>
33 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
34 #include <comphelper/namedvaluecollection.hxx>
36 namespace utl
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::lang;
41 using namespace ::com::sun::star::util;
42 using namespace ::com::sun::star::container;
43 using namespace ::com::sun::star::configuration;
45 //= OConfigurationNode
47 OConfigurationNode::OConfigurationNode(const Reference< XInterface >& _rxNode )
48 :m_bEscapeNames(false)
50 OSL_ENSURE(_rxNode.is(), "OConfigurationNode::OConfigurationNode: invalid node interface!");
51 if (_rxNode.is())
53 // collect all interfaces necessary
54 m_xHierarchyAccess.set(_rxNode, UNO_QUERY);
55 m_xDirectAccess.set(_rxNode, UNO_QUERY);
57 // reset _all_ interfaces if _one_ of them is not supported
58 if (!m_xHierarchyAccess.is() || !m_xDirectAccess.is())
60 m_xHierarchyAccess = nullptr;
61 m_xDirectAccess = nullptr;
64 // now for the non-critical interfaces
65 m_xReplaceAccess.set(_rxNode, UNO_QUERY);
66 m_xContainerAccess.set(_rxNode, UNO_QUERY);
69 Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY);
70 if (xConfigNodeComp.is())
71 startComponentListening(xConfigNodeComp);
73 if (isValid())
74 m_bEscapeNames = isSetNode() && Reference< XStringEscape >::query(m_xDirectAccess).is();
77 OConfigurationNode::OConfigurationNode(const OConfigurationNode& _rSource)
78 : OEventListenerAdapter()
79 , m_xHierarchyAccess(_rSource.m_xHierarchyAccess)
80 , m_xDirectAccess(_rSource.m_xDirectAccess)
81 , m_xReplaceAccess(_rSource.m_xReplaceAccess)
82 , m_xContainerAccess(_rSource.m_xContainerAccess)
83 , m_bEscapeNames(_rSource.m_bEscapeNames)
85 Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY);
86 if (xConfigNodeComp.is())
87 startComponentListening(xConfigNodeComp);
90 OConfigurationNode::OConfigurationNode(OConfigurationNode&& _rSource)
91 : OEventListenerAdapter()
92 , m_xHierarchyAccess(std::move(_rSource.m_xHierarchyAccess))
93 , m_xDirectAccess(std::move(_rSource.m_xDirectAccess))
94 , m_xReplaceAccess(std::move(_rSource.m_xReplaceAccess))
95 , m_xContainerAccess(std::move(_rSource.m_xContainerAccess))
96 , m_bEscapeNames(std::move(_rSource.m_bEscapeNames))
98 Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY);
99 if (xConfigNodeComp.is())
100 startComponentListening(xConfigNodeComp);
103 OConfigurationNode& OConfigurationNode::operator=(const OConfigurationNode& _rSource)
105 stopAllComponentListening();
107 m_xHierarchyAccess = _rSource.m_xHierarchyAccess;
108 m_xDirectAccess = _rSource.m_xDirectAccess;
109 m_xContainerAccess = _rSource.m_xContainerAccess;
110 m_xReplaceAccess = _rSource.m_xReplaceAccess;
111 m_bEscapeNames = _rSource.m_bEscapeNames;
113 Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY);
114 if (xConfigNodeComp.is())
115 startComponentListening(xConfigNodeComp);
117 return *this;
120 OConfigurationNode& OConfigurationNode::operator=(OConfigurationNode&& _rSource)
122 stopAllComponentListening();
124 m_xHierarchyAccess = std::move(_rSource.m_xHierarchyAccess);
125 m_xDirectAccess = std::move(_rSource.m_xDirectAccess);
126 m_xContainerAccess = std::move(_rSource.m_xContainerAccess);
127 m_xReplaceAccess = std::move(_rSource.m_xReplaceAccess);
128 m_bEscapeNames = std::move(_rSource.m_bEscapeNames);
130 Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY);
131 if (xConfigNodeComp.is())
132 startComponentListening(xConfigNodeComp);
134 return *this;
137 void OConfigurationNode::_disposing( const EventObject& _rSource )
139 Reference< XComponent > xDisposingSource(_rSource.Source, UNO_QUERY);
140 Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY);
141 if (xDisposingSource.get() == xConfigNodeComp.get())
142 clear();
145 OUString OConfigurationNode::getLocalName() const
147 OUString sLocalName;
150 Reference< XNamed > xNamed( m_xDirectAccess, UNO_QUERY_THROW );
151 sLocalName = xNamed->getName();
153 catch( const Exception& )
155 DBG_UNHANDLED_EXCEPTION("unotools");
157 return sLocalName;
160 OUString OConfigurationNode::normalizeName(const OUString& _rName, NAMEORIGIN _eOrigin) const
162 OUString sName(_rName);
163 if (m_bEscapeNames)
165 Reference< XStringEscape > xEscaper(m_xDirectAccess, UNO_QUERY);
166 if (xEscaper.is() && !sName.isEmpty())
170 if (NO_CALLER == _eOrigin)
171 sName = xEscaper->escapeString(sName);
172 else
173 sName = xEscaper->unescapeString(sName);
175 catch(Exception&)
177 DBG_UNHANDLED_EXCEPTION("unotools");
181 return sName;
184 Sequence< OUString > OConfigurationNode::getNodeNames() const noexcept
186 OSL_ENSURE(m_xDirectAccess.is(), "OConfigurationNode::getNodeNames: object is invalid!");
187 Sequence< OUString > aReturn;
188 if (m_xDirectAccess.is())
192 aReturn = m_xDirectAccess->getElementNames();
193 // normalize the names
194 std::transform(std::cbegin(aReturn), std::cend(aReturn), aReturn.getArray(),
195 [this](const OUString& rName) -> OUString { return normalizeName(rName, NO_CONFIGURATION); });
197 catch(Exception&)
199 TOOLS_WARN_EXCEPTION( "unotools", "OConfigurationNode::getNodeNames");
203 return aReturn;
206 bool OConfigurationNode::removeNode(const OUString& _rName) const noexcept
208 OSL_ENSURE(m_xContainerAccess.is(), "OConfigurationNode::removeNode: object is invalid!");
209 if (m_xContainerAccess.is())
213 OUString sName = normalizeName(_rName, NO_CALLER);
214 m_xContainerAccess->removeByName(sName);
215 return true;
217 catch (NoSuchElementException&)
219 SAL_WARN( "unotools", "OConfigurationNode::removeNode: there is no element named: " << _rName );
221 catch(Exception&)
223 TOOLS_WARN_EXCEPTION( "unotools", "OConfigurationNode::removeNode");
226 return false;
229 OConfigurationNode OConfigurationNode::insertNode(const OUString& _rName,const Reference< XInterface >& _xNode) const noexcept
231 if(_xNode.is())
235 OUString sName = normalizeName(_rName, NO_CALLER);
236 m_xContainerAccess->insertByName(sName, Any(_xNode));
237 // if we're here, all was ok ...
238 return OConfigurationNode( _xNode );
240 catch(const Exception&)
242 DBG_UNHANDLED_EXCEPTION("unotools");
245 // dispose the child if it has already been created, but could not be inserted
246 Reference< XComponent > xChildComp(_xNode, UNO_QUERY);
247 if (xChildComp.is())
248 try { xChildComp->dispose(); } catch(Exception&) { }
251 return OConfigurationNode();
254 OConfigurationNode OConfigurationNode::createNode(const OUString& _rName) const noexcept
256 Reference< XSingleServiceFactory > xChildFactory(m_xContainerAccess, UNO_QUERY);
257 OSL_ENSURE(xChildFactory.is(), "OConfigurationNode::createNode: object is invalid or read-only!");
259 if (xChildFactory.is()) // implies m_xContainerAccess.is()
261 Reference< XInterface > xNewChild;
264 xNewChild = xChildFactory->createInstance();
266 catch(const Exception&)
268 DBG_UNHANDLED_EXCEPTION("unotools");
270 return insertNode(_rName,xNewChild);
273 return OConfigurationNode();
276 OConfigurationNode OConfigurationNode::openNode(const OUString& _rPath) const noexcept
278 OSL_ENSURE(m_xDirectAccess.is(), "OConfigurationNode::openNode: object is invalid!");
279 OSL_ENSURE(m_xHierarchyAccess.is(), "OConfigurationNode::openNode: object is invalid!");
282 OUString sNormalized = normalizeName(_rPath, NO_CALLER);
284 Reference< XInterface > xNode;
285 if (m_xDirectAccess.is() && m_xDirectAccess->hasByName(sNormalized))
287 xNode.set(
288 m_xDirectAccess->getByName(sNormalized), css::uno::UNO_QUERY);
289 if (!xNode.is())
290 OSL_FAIL("OConfigurationNode::openNode: could not open the node!");
292 else if (m_xHierarchyAccess.is())
294 xNode.set(
295 m_xHierarchyAccess->getByHierarchicalName(_rPath),
296 css::uno::UNO_QUERY);
297 if (!xNode.is())
298 OSL_FAIL("OConfigurationNode::openNode: could not open the node!");
300 if (xNode.is())
301 return OConfigurationNode( xNode );
303 catch(const NoSuchElementException&)
305 SAL_WARN( "unotools", "OConfigurationNode::openNode: there is no element named " << _rPath );
307 catch(Exception&)
309 TOOLS_WARN_EXCEPTION( "unotools", "OConfigurationNode::openNode: caught an exception while retrieving the node!");
311 return OConfigurationNode();
314 bool OConfigurationNode::isSetNode() const
316 bool bIsSet = false;
317 Reference< XServiceInfo > xSI(m_xHierarchyAccess, UNO_QUERY);
318 if (xSI.is())
320 try { bIsSet = xSI->supportsService(u"com.sun.star.configuration.SetAccess"_ustr); }
321 catch(Exception&) { }
323 return bIsSet;
326 bool OConfigurationNode::hasByHierarchicalName( const OUString& _rName ) const noexcept
328 OSL_ENSURE( m_xHierarchyAccess.is(), "OConfigurationNode::hasByHierarchicalName: no hierarchy access!" );
331 if ( m_xHierarchyAccess.is() )
333 OUString sName = normalizeName( _rName, NO_CALLER );
334 return m_xHierarchyAccess->hasByHierarchicalName( sName );
337 catch(Exception&)
340 return false;
343 bool OConfigurationNode::hasByName(const OUString& _rName) const noexcept
345 OSL_ENSURE(m_xDirectAccess.is(), "OConfigurationNode::hasByName: object is invalid!");
348 OUString sName = normalizeName(_rName, NO_CALLER);
349 if (m_xDirectAccess.is())
350 return m_xDirectAccess->hasByName(sName);
352 catch(Exception&)
355 return false;
358 bool OConfigurationNode::setNodeValue(const OUString& _rPath, const Any& _rValue) const noexcept
360 bool bResult = false;
362 OSL_ENSURE(m_xReplaceAccess.is(), "OConfigurationNode::setNodeValue: object is invalid!");
363 if (m_xReplaceAccess.is())
367 // check if _rPath is a level-1 path
368 OUString sNormalizedName = normalizeName(_rPath, NO_CALLER);
369 if (m_xReplaceAccess->hasByName(sNormalizedName))
371 m_xReplaceAccess->replaceByName(sNormalizedName, _rValue);
372 bResult = true;
375 // check if the name refers to an indirect descendant
376 else if (m_xHierarchyAccess.is() && m_xHierarchyAccess->hasByHierarchicalName(_rPath))
378 OSL_ASSERT(!_rPath.isEmpty());
380 OUString sParentPath, sLocalName;
382 if ( splitLastFromConfigurationPath(_rPath, sParentPath, sLocalName) )
384 OConfigurationNode aParentAccess = openNode(sParentPath);
385 if (aParentAccess.isValid())
386 bResult = aParentAccess.setNodeValue(sLocalName, _rValue);
388 else
390 m_xReplaceAccess->replaceByName(sLocalName, _rValue);
391 bResult = true;
396 catch(Exception&)
398 TOOLS_WARN_EXCEPTION( "unotools", "OConfigurationNode::setNodeValue: could not replace the value");
402 return bResult;
405 Any OConfigurationNode::getNodeValue(const OUString& _rPath) const noexcept
407 OSL_ENSURE(m_xDirectAccess.is(), "OConfigurationNode::hasByName: object is invalid!");
408 OSL_ENSURE(m_xHierarchyAccess.is(), "OConfigurationNode::hasByName: object is invalid!");
409 Any aReturn;
412 OUString sNormalizedPath = normalizeName(_rPath, NO_CALLER);
413 if (m_xDirectAccess.is() && m_xDirectAccess->hasByName(sNormalizedPath) )
415 aReturn = m_xDirectAccess->getByName(sNormalizedPath);
417 else if (m_xHierarchyAccess.is())
419 aReturn = m_xHierarchyAccess->getByHierarchicalName(_rPath);
422 catch(const NoSuchElementException&)
424 DBG_UNHANDLED_EXCEPTION("unotools");
426 return aReturn;
429 void OConfigurationNode::clear() noexcept
431 m_xHierarchyAccess.clear();
432 m_xDirectAccess.clear();
433 m_xReplaceAccess.clear();
434 m_xContainerAccess.clear();
437 //= helper
439 namespace
442 Reference< XMultiServiceFactory > lcl_getConfigProvider( const Reference<XComponentContext> & i_rContext )
446 Reference< XMultiServiceFactory > xProvider = theDefaultProvider::get( i_rContext );
447 return xProvider;
449 catch ( const Exception& )
451 DBG_UNHANDLED_EXCEPTION("unotools");
453 return nullptr;
456 Reference< XInterface > lcl_createConfigurationRoot( const Reference< XMultiServiceFactory >& i_rxConfigProvider,
457 const OUString& i_rNodePath, const bool i_bUpdatable, const sal_Int32 i_nDepth )
459 ENSURE_OR_RETURN( i_rxConfigProvider.is(), "invalid provider", nullptr );
462 ::comphelper::NamedValueCollection aArgs;
463 aArgs.put( u"nodepath"_ustr, i_rNodePath );
464 aArgs.put( u"depth"_ustr, i_nDepth );
466 OUString sAccessService( i_bUpdatable ?
467 u"com.sun.star.configuration.ConfigurationUpdateAccess"_ustr :
468 u"com.sun.star.configuration.ConfigurationAccess"_ustr);
470 Reference< XInterface > xRoot(
471 i_rxConfigProvider->createInstanceWithArguments( sAccessService, aArgs.getWrappedPropertyValues() ),
472 UNO_SET_THROW
474 return xRoot;
476 catch ( const Exception& )
478 DBG_UNHANDLED_EXCEPTION("unotools");
480 return nullptr;
484 OConfigurationTreeRoot::OConfigurationTreeRoot( const Reference< XInterface >& _rxRootNode )
485 :OConfigurationNode( _rxRootNode )
486 ,m_xCommitter( _rxRootNode, UNO_QUERY )
490 OConfigurationTreeRoot::OConfigurationTreeRoot( const Reference<XComponentContext> & i_rContext, const OUString& i_rNodePath, const bool i_bUpdatable )
491 :OConfigurationNode( lcl_createConfigurationRoot( lcl_getConfigProvider( i_rContext ),
492 i_rNodePath, i_bUpdatable, -1 ) )
493 ,m_xCommitter()
495 if ( i_bUpdatable )
497 m_xCommitter.set( getUNONode(), UNO_QUERY );
498 OSL_ENSURE( m_xCommitter.is(), "OConfigurationTreeRoot::OConfigurationTreeRoot: could not create an updatable node!" );
502 void OConfigurationTreeRoot::clear() noexcept
504 OConfigurationNode::clear();
505 m_xCommitter.clear();
508 bool OConfigurationTreeRoot::commit() const noexcept
510 OSL_ENSURE(isValid(), "OConfigurationTreeRoot::commit: object is invalid!");
511 if (!isValid())
512 return false;
513 OSL_ENSURE(m_xCommitter.is(), "OConfigurationTreeRoot::commit: I'm a readonly node!");
514 if (!m_xCommitter.is())
515 return false;
519 m_xCommitter->commitChanges();
520 return true;
522 catch(const Exception&)
524 DBG_UNHANDLED_EXCEPTION("unotools");
526 return false;
529 OConfigurationTreeRoot OConfigurationTreeRoot::createWithProvider(const Reference< XMultiServiceFactory >& _rxConfProvider, const OUString& _rPath, sal_Int32 _nDepth, CREATION_MODE _eMode)
531 Reference< XInterface > xRoot( lcl_createConfigurationRoot(
532 _rxConfProvider, _rPath, _eMode != CM_READONLY, _nDepth ) );
533 if ( xRoot.is() )
534 return OConfigurationTreeRoot( xRoot );
535 return OConfigurationTreeRoot();
538 OConfigurationTreeRoot OConfigurationTreeRoot::createWithComponentContext( const Reference< XComponentContext >& _rxContext, const OUString& _rPath, sal_Int32 _nDepth, CREATION_MODE _eMode )
540 return createWithProvider( lcl_getConfigProvider( _rxContext ), _rPath, _nDepth, _eMode );
543 OConfigurationTreeRoot OConfigurationTreeRoot::tryCreateWithComponentContext( const Reference< XComponentContext >& rxContext,
544 const OUString& _rPath, sal_Int32 _nDepth , CREATION_MODE _eMode )
546 OSL_ENSURE( rxContext.is(), "OConfigurationTreeRoot::tryCreateWithComponentContext: invalid XComponentContext!" );
549 Reference< XMultiServiceFactory > xConfigFactory = theDefaultProvider::get( rxContext );
550 return createWithProvider( xConfigFactory, _rPath, _nDepth, _eMode );
552 catch(const Exception&)
554 // silence this, 'cause the contract of this method states "no assertions"
556 return OConfigurationTreeRoot();
559 } // namespace utl
561 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */