Avoid potential negative array index access to cached text.
[LibreOffice.git] / chart2 / source / tools / PropertyHelper.cxx
blob48e21eccaf25b484e946b36cafa4156fa927bf7e
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 <PropertyHelper.hxx>
21 #include <com/sun/star/container/XNameContainer.hpp>
22 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
23 #include <docmodel/uno/UnoGradientTools.hxx>
24 #include <comphelper/sequence.hxx>
25 #include <osl/diagnose.h>
26 #include <comphelper/diagnose_ex.hxx>
27 #include <o3tl/string_view.hxx>
29 #include <utility>
30 #include <vector>
31 #include <algorithm>
32 #include <iterator>
34 using namespace ::com::sun::star;
35 using namespace ::com::sun::star::beans;
36 using ::com::sun::star::uno::Any;
37 using ::com::sun::star::uno::Reference;
39 namespace
41 struct lcl_EqualsElement
43 explicit lcl_EqualsElement( Any rValue, const Reference< container::XNameAccess > & xAccess )
44 : m_aValue(std::move( rValue )), m_xAccess( xAccess )
46 OSL_ASSERT( m_xAccess.is());
49 bool operator() ( const OUString & rName )
51 try
53 return (m_xAccess->getByName( rName ) == m_aValue);
55 catch( const uno::Exception & )
57 DBG_UNHANDLED_EXCEPTION("chart2");
59 return false;
62 private:
63 Any m_aValue;
64 Reference< container::XNameAccess > m_xAccess;
67 struct lcl_StringMatches
69 explicit lcl_StringMatches( OUString aCmpStr ) :
70 m_aCmpStr(std::move( aCmpStr ))
73 bool operator() ( std::u16string_view rStr )
75 return o3tl::starts_with( rStr, m_aCmpStr );
78 private:
79 OUString m_aCmpStr;
82 struct lcl_OUStringRestToInt32
84 explicit lcl_OUStringRestToInt32( sal_Int32 nPrefixLength ) :
85 m_nPrefixLength( nPrefixLength )
87 sal_Int32 operator() ( std::u16string_view rStr )
89 if( m_nPrefixLength > static_cast<sal_Int32>(rStr.size()) )
90 return 0;
91 return o3tl::toInt32(rStr.substr( m_nPrefixLength ));
93 private:
94 sal_Int32 m_nPrefixLength;
97 /** adds a fill gradient, fill hatch, fill bitmap, fill transparency gradient,
98 line dash or line marker to the corresponding name container with a unique
99 name.
101 @param rPrefix
102 The prefix used for automated name generation.
104 @param rPreferredName
105 If this string is not empty it is used as name if it is unique in the
106 table. Otherwise a new name is generated using pPrefix.
108 @return the new name under which the property was stored in the table
110 OUString lcl_addNamedPropertyUniqueNameToTable(
111 const Any & rValue,
112 const Reference< container::XNameContainer > & xNameContainer,
113 const OUString & rPrefix,
114 const OUString & rPreferredName )
116 if( ! xNameContainer.is() ||
117 ! rValue.hasValue() )
118 return rPreferredName;
120 Any aValue(rValue);
122 if ( rValue.has<css::awt::Gradient>())
124 // tdf#158421 the lists for Gradients needs awt::Gradient2
125 // as type, convert input data if needed (and warn about it,
126 // the caller should be changed to offer the needed type)
127 SAL_WARN("chart2","input value needs to be awt::Gradient2");
128 const basegfx::BGradient aTemp(model::gradient::getFromAny(rValue));
129 aValue <<= model::gradient::createUnoGradient2(aTemp);
132 if ( aValue.getValueType() != xNameContainer->getElementType())
133 return rPreferredName;
137 Reference< container::XNameAccess > xNameAccess( xNameContainer, uno::UNO_QUERY_THROW );
138 const uno::Sequence<OUString> aElementNames = xNameAccess->getElementNames();
139 auto it = std::find_if( aElementNames.begin(), aElementNames.end(), lcl_EqualsElement( aValue, xNameAccess ));
141 // element found => return name
142 if( it != aElementNames.end())
143 return *it;
145 // element not found in container
146 OUString aUniqueName;
148 // check if preferred name is already used
149 if( !rPreferredName.isEmpty())
151 auto aIt = std::find( aElementNames.begin(), aElementNames.end(), rPreferredName );
152 if( aIt == aElementNames.end())
153 aUniqueName = rPreferredName;
156 if( aUniqueName.isEmpty())
158 auto aNames( comphelper::sequenceToContainer<std::vector< OUString >>( aElementNames ));
159 // create a unique id using the prefix plus a number
160 std::vector< sal_Int32 > aNumbers;
161 std::vector< OUString >::iterator aNonConstIt(
162 std::partition( aNames.begin(), aNames.end(), lcl_StringMatches( rPrefix )));
163 std::transform( aNames.begin(), aNonConstIt,
164 back_inserter( aNumbers ),
165 lcl_OUStringRestToInt32( rPrefix.getLength() ));
166 std::vector< sal_Int32 >::const_iterator aMaxIt(
167 std::max_element( aNumbers.begin(), aNumbers.end()));
169 sal_Int32 nIndex = 1;
170 if( aMaxIt != aNumbers.end())
171 nIndex = (*aMaxIt) + 1;
173 aUniqueName = rPrefix + OUString::number( nIndex );
176 OSL_ASSERT( !aUniqueName.isEmpty());
177 xNameContainer->insertByName( aUniqueName, aValue );
178 return aUniqueName;
180 catch( const uno::Exception & )
182 DBG_UNHANDLED_EXCEPTION("chart2");
185 return rPreferredName;
188 } // anonymous namespace
190 namespace chart::PropertyHelper
193 OUString addLineDashUniqueNameToTable(
194 const Any & rValue,
195 const Reference< lang::XMultiServiceFactory > & xFact,
196 const OUString & rPreferredName )
198 if( xFact.is())
200 Reference< container::XNameContainer > xNameCnt(
201 xFact->createInstance( "com.sun.star.drawing.DashTable"),
202 uno::UNO_QUERY );
203 if( xNameCnt.is())
204 return lcl_addNamedPropertyUniqueNameToTable(
205 rValue, xNameCnt, "ChartDash ", rPreferredName );
207 return OUString();
210 OUString addGradientUniqueNameToTable(
211 const Any & rValue,
212 const Reference< lang::XMultiServiceFactory > & xFact,
213 const OUString & rPreferredName )
215 if( xFact.is())
217 Reference< container::XNameContainer > xNameCnt(
218 xFact->createInstance( "com.sun.star.drawing.GradientTable"),
219 uno::UNO_QUERY );
220 if( xNameCnt.is())
221 return lcl_addNamedPropertyUniqueNameToTable(
222 rValue, xNameCnt, "ChartGradient ", rPreferredName );
224 return OUString();
227 OUString addTransparencyGradientUniqueNameToTable(
228 const Any & rValue,
229 const Reference< lang::XMultiServiceFactory > & xFact,
230 const OUString & rPreferredName )
232 if( xFact.is())
234 Reference< container::XNameContainer > xNameCnt(
235 xFact->createInstance( "com.sun.star.drawing.TransparencyGradientTable"),
236 uno::UNO_QUERY );
237 if( xNameCnt.is())
238 return lcl_addNamedPropertyUniqueNameToTable(
239 rValue, xNameCnt, "ChartTransparencyGradient ", rPreferredName );
241 return OUString();
244 OUString addHatchUniqueNameToTable(
245 const Any & rValue,
246 const Reference< lang::XMultiServiceFactory > & xFact,
247 const OUString & rPreferredName )
249 if( xFact.is())
251 Reference< container::XNameContainer > xNameCnt(
252 xFact->createInstance( "com.sun.star.drawing.HatchTable"),
253 uno::UNO_QUERY );
254 if( xNameCnt.is())
255 return lcl_addNamedPropertyUniqueNameToTable(
256 rValue, xNameCnt, "ChartHatch ", rPreferredName );
258 return OUString();
261 OUString addBitmapUniqueNameToTable(
262 const Any & rValue,
263 const Reference< lang::XMultiServiceFactory > & xFact,
264 const OUString & rPreferredName )
266 if( xFact.is())
268 Reference< container::XNameContainer > xNameCnt(
269 xFact->createInstance( "com.sun.star.drawing.BitmapTable"),
270 uno::UNO_QUERY );
271 if( xNameCnt.is())
272 return lcl_addNamedPropertyUniqueNameToTable(
273 rValue, xNameCnt, "ChartBitmap ", rPreferredName );
275 return OUString();
278 void setPropertyValueAny( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const uno::Any & rAny )
280 tPropertyValueMap::iterator aIt( rOutMap.find( key ));
281 if( aIt == rOutMap.end())
282 rOutMap.emplace( key, rAny );
283 else
284 (*aIt).second = rAny;
287 template<>
288 void setPropertyValue< css::uno::Any >( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const css::uno::Any & rAny )
290 setPropertyValueAny( rOutMap, key, rAny );
293 void setPropertyValueDefaultAny( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const uno::Any & rAny )
295 OSL_ENSURE( rOutMap.end() == rOutMap.find( key ), "Default already exists for property" );
296 setPropertyValue( rOutMap, key, rAny );
299 template<>
300 void setPropertyValueDefault< css::uno::Any >( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const css::uno::Any & rAny )
302 setPropertyValueDefaultAny( rOutMap, key, rAny );
305 void setEmptyPropertyValueDefault( tPropertyValueMap & rOutMap, tPropertyValueMapKey key )
307 setPropertyValueDefault( rOutMap, key, uno::Any());
310 } // namespace chart::PropertyHelper
312 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */