1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_comphelper.hxx"
26 #include <comphelper/namedvaluecollection.hxx>
27 
28 /** === begin UNO includes === **/
29 #include <com/sun/star/beans/NamedValue.hpp>
30 #include <com/sun/star/lang/IllegalArgumentException.hpp>
31 #include <com/sun/star/beans/PropertyState.hpp>
32 /** === end UNO includes === **/
33 
34 #include <rtl/ustrbuf.hxx>
35 #include <rtl/strbuf.hxx>
36 #include <osl/diagnose.h>
37 
38 #include <hash_map>
39 #include <functional>
40 #include <algorithm>
41 
42 //........................................................................
43 namespace comphelper
44 {
45 //........................................................................
46 
47     /** === begin UNO using === **/
48     using ::com::sun::star::uno::Any;
49     using ::com::sun::star::uno::Sequence;
50     using ::com::sun::star::beans::PropertyValue;
51     using ::com::sun::star::beans::NamedValue;
52     using ::com::sun::star::uno::Type;
53     using ::com::sun::star::uno::cpp_acquire;
54     using ::com::sun::star::uno::cpp_release;
55     using ::com::sun::star::uno::cpp_queryInterface;
56     using ::com::sun::star::lang::IllegalArgumentException;
57     using ::com::sun::star::beans::NamedValue;
58     using ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
59     /** === end UNO using === **/
60 
61     //====================================================================
62 	//= NamedValueCollection_Impl
63 	//====================================================================
64     typedef ::std::hash_map< ::rtl::OUString, Any, ::rtl::OUStringHash >    NamedValueRepository;
65 
66     struct NamedValueCollection_Impl
67     {
68         NamedValueRepository    aValues;
69     };
70 
71     //====================================================================
72 	//= NamedValueCollection
73 	//====================================================================
74 	//--------------------------------------------------------------------
NamedValueCollection()75     NamedValueCollection::NamedValueCollection()
76         :m_pImpl( new NamedValueCollection_Impl )
77     {
78     }
79 
80 	//--------------------------------------------------------------------
NamedValueCollection(const NamedValueCollection & _rCopySource)81     NamedValueCollection::NamedValueCollection( const NamedValueCollection& _rCopySource )
82         :m_pImpl( new NamedValueCollection_Impl )
83     {
84         *this = _rCopySource;
85     }
86 
87 	//--------------------------------------------------------------------
operator =(const NamedValueCollection & i_rCopySource)88     NamedValueCollection& NamedValueCollection::operator=( const NamedValueCollection& i_rCopySource )
89     {
90         m_pImpl->aValues = i_rCopySource.m_pImpl->aValues;
91         return *this;
92     }
93 
94 	//--------------------------------------------------------------------
NamedValueCollection(const Any & _rElements)95     NamedValueCollection::NamedValueCollection( const Any& _rElements )
96         :m_pImpl( new NamedValueCollection_Impl )
97     {
98         impl_assign( _rElements );
99     }
100 
101 	//--------------------------------------------------------------------
NamedValueCollection(const Sequence<Any> & _rArguments)102     NamedValueCollection::NamedValueCollection( const Sequence< Any >& _rArguments )
103         :m_pImpl( new NamedValueCollection_Impl )
104     {
105         impl_assign( _rArguments );
106     }
107 
108 	//--------------------------------------------------------------------
NamedValueCollection(const Sequence<PropertyValue> & _rArguments)109     NamedValueCollection::NamedValueCollection( const Sequence< PropertyValue >& _rArguments )
110         :m_pImpl( new NamedValueCollection_Impl )
111     {
112         impl_assign( _rArguments );
113     }
114 
115 	//--------------------------------------------------------------------
NamedValueCollection(const Sequence<NamedValue> & _rArguments)116     NamedValueCollection::NamedValueCollection( const Sequence< NamedValue >& _rArguments )
117         :m_pImpl( new NamedValueCollection_Impl )
118     {
119         impl_assign( _rArguments );
120     }
121 
122 	//--------------------------------------------------------------------
~NamedValueCollection()123     NamedValueCollection::~NamedValueCollection()
124     {
125     }
126 
127 	//--------------------------------------------------------------------
canExtractFrom(::com::sun::star::uno::Any const & i_value)128     bool NamedValueCollection::canExtractFrom( ::com::sun::star::uno::Any const & i_value )
129     {
130         Type const & aValueType = i_value.getValueType();
131         if  (   aValueType.equals( ::cppu::UnoType< PropertyValue >::get() )
132             ||  aValueType.equals( ::cppu::UnoType< NamedValue >::get() )
133             ||  aValueType.equals( ::cppu::UnoType< Sequence< PropertyValue > >::get() )
134             ||  aValueType.equals( ::cppu::UnoType< Sequence< NamedValue > >::get() )
135             )
136             return true;
137         return false;
138     }
139 
140 	//--------------------------------------------------------------------
merge(const NamedValueCollection & _rAdditionalValues,bool _bOverwriteExisting)141     NamedValueCollection& NamedValueCollection::merge( const NamedValueCollection& _rAdditionalValues, bool _bOverwriteExisting )
142     {
143         for (   NamedValueRepository::const_iterator namedValue = _rAdditionalValues.m_pImpl->aValues.begin();
144                 namedValue != _rAdditionalValues.m_pImpl->aValues.end();
145                 ++namedValue
146             )
147         {
148             if ( _bOverwriteExisting || !impl_has( namedValue->first ) )
149                 impl_put( namedValue->first, namedValue->second );
150         }
151 
152         return *this;
153     }
154 
155 	//--------------------------------------------------------------------
size() const156     size_t NamedValueCollection::size() const
157     {
158         return m_pImpl->aValues.size();
159     }
160 
161 	//--------------------------------------------------------------------
empty() const162     bool NamedValueCollection::empty() const
163     {
164         return m_pImpl->aValues.empty();
165     }
166 
167 	//--------------------------------------------------------------------
getNames() const168     ::std::vector< ::rtl::OUString > NamedValueCollection::getNames() const
169     {
170         ::std::vector< ::rtl::OUString > aNames( m_pImpl->aValues.size() );
171         ::std::transform(
172             m_pImpl->aValues.begin(),
173             m_pImpl->aValues.end(),
174             aNames.begin(),
175             ::std::select1st< NamedValueRepository::value_type >()
176         );
177         return aNames;
178     }
179 
180 	//--------------------------------------------------------------------
impl_assign(const Any & i_rWrappedElements)181     void NamedValueCollection::impl_assign( const Any& i_rWrappedElements )
182     {
183         Sequence< NamedValue > aNamedValues;
184         Sequence< PropertyValue > aPropertyValues;
185         NamedValue aNamedValue;
186         PropertyValue aPropertyValue;
187 
188         if ( i_rWrappedElements >>= aNamedValues )
189             impl_assign( aNamedValues );
190         else if ( i_rWrappedElements >>= aPropertyValues )
191             impl_assign( aPropertyValues );
192         else if ( i_rWrappedElements >>= aNamedValue )
193             impl_assign( Sequence< NamedValue >( &aNamedValue, 1 ) );
194         else if ( i_rWrappedElements >>= aPropertyValue )
195             impl_assign( Sequence< PropertyValue >( &aPropertyValue, 1 ) );
196         else
197             OSL_ENSURE( !i_rWrappedElements.hasValue(), "NamedValueCollection::impl_assign(Any): unsupported type!" );
198     }
199 
200 	//--------------------------------------------------------------------
impl_assign(const Sequence<Any> & _rArguments)201     void NamedValueCollection::impl_assign( const Sequence< Any >& _rArguments )
202     {
203         {
204             NamedValueRepository aEmpty;
205             m_pImpl->aValues.swap( aEmpty );
206         }
207 
208         PropertyValue aPropertyValue;
209         NamedValue aNamedValue;
210 
211         const Any* pArgument = _rArguments.getConstArray();
212         const Any* pArgumentEnd = _rArguments.getConstArray() + _rArguments.getLength();
213         for ( ; pArgument != pArgumentEnd; ++pArgument )
214         {
215             if ( *pArgument >>= aPropertyValue )
216                 m_pImpl->aValues[ aPropertyValue.Name ] = aPropertyValue.Value;
217             else if ( *pArgument >>= aNamedValue )
218                 m_pImpl->aValues[ aNamedValue.Name ] = aNamedValue.Value;
219 #if OSL_DEBUG_LEVEL > 0
220             else if ( pArgument->hasValue() )
221             {
222                 ::rtl::OStringBuffer message;
223                 message.append( "NamedValueCollection::impl_assign: encountered a value type which I cannot handle:\n" );
224                 message.append( ::rtl::OUStringToOString( pArgument->getValueTypeName(), RTL_TEXTENCODING_ASCII_US ) );
225                 OSL_ENSURE( false, message.getStr() );
226             }
227 #endif
228         }
229     }
230 
231 	//--------------------------------------------------------------------
impl_assign(const Sequence<PropertyValue> & _rArguments)232     void NamedValueCollection::impl_assign( const Sequence< PropertyValue >& _rArguments )
233     {
234         {
235             NamedValueRepository aEmpty;
236             m_pImpl->aValues.swap( aEmpty );
237         }
238 
239         const PropertyValue* pArgument = _rArguments.getConstArray();
240         const PropertyValue* pArgumentEnd = _rArguments.getConstArray() + _rArguments.getLength();
241         for ( ; pArgument != pArgumentEnd; ++pArgument )
242             m_pImpl->aValues[ pArgument->Name ] = pArgument->Value;
243     }
244 
245 	//--------------------------------------------------------------------
impl_assign(const Sequence<NamedValue> & _rArguments)246     void NamedValueCollection::impl_assign( const Sequence< NamedValue >& _rArguments )
247     {
248         {
249             NamedValueRepository aEmpty;
250             m_pImpl->aValues.swap( aEmpty );
251         }
252 
253         const NamedValue* pArgument = _rArguments.getConstArray();
254         const NamedValue* pArgumentEnd = _rArguments.getConstArray() + _rArguments.getLength();
255         for ( ; pArgument != pArgumentEnd; ++pArgument )
256             m_pImpl->aValues[ pArgument->Name ] = pArgument->Value;
257     }
258 
259 	//--------------------------------------------------------------------
get_ensureType(const::rtl::OUString & _rValueName,void * _pValueLocation,const Type & _rExpectedValueType) const260     bool NamedValueCollection::get_ensureType( const ::rtl::OUString& _rValueName, void* _pValueLocation, const Type& _rExpectedValueType ) const
261     {
262         NamedValueRepository::const_iterator pos = m_pImpl->aValues.find( _rValueName );
263         if ( pos != m_pImpl->aValues.end() )
264         {
265 		    if ( uno_type_assignData(
266 			        _pValueLocation, _rExpectedValueType.getTypeLibType(),
267 				    const_cast< void* >( pos->second.getValue() ), pos->second.getValueType().getTypeLibType(),
268 			    	reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
269                     reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
270                     reinterpret_cast< uno_ReleaseFunc >( cpp_release )
271                 ) )
272                 // argument exists, and could be extracted
273                 return true;
274 
275             // argument exists, but is of wrong type
276             ::rtl::OUStringBuffer aBuffer;
277             aBuffer.appendAscii( "Invalid value type for '" );
278             aBuffer.append     ( _rValueName );
279             aBuffer.appendAscii( "'.\nExpected: " );
280             aBuffer.append     ( _rExpectedValueType.getTypeName() );
281             aBuffer.appendAscii( "\nFound: " );
282             aBuffer.append     ( pos->second.getValueType().getTypeName() );
283             throw IllegalArgumentException( aBuffer.makeStringAndClear(), NULL, 0 );
284         }
285 
286         // argument does not exist
287         return false;
288     }
289 
290     //--------------------------------------------------------------------
impl_get(const::rtl::OUString & _rValueName) const291     const Any& NamedValueCollection::impl_get( const ::rtl::OUString& _rValueName ) const
292     {
293         NamedValueRepository::const_iterator pos = m_pImpl->aValues.find( _rValueName );
294         if ( pos != m_pImpl->aValues.end() )
295             return pos->second;
296 
297         static Any aEmptyDefault;
298         return aEmptyDefault;
299     }
300 
301     //--------------------------------------------------------------------
impl_has(const::rtl::OUString & _rValueName) const302     bool NamedValueCollection::impl_has( const ::rtl::OUString& _rValueName ) const
303     {
304         NamedValueRepository::const_iterator pos = m_pImpl->aValues.find( _rValueName );
305         return ( pos != m_pImpl->aValues.end() );
306     }
307 
308     //--------------------------------------------------------------------
impl_put(const::rtl::OUString & _rValueName,const Any & _rValue)309     bool NamedValueCollection::impl_put( const ::rtl::OUString& _rValueName, const Any& _rValue )
310     {
311         bool bHas = impl_has( _rValueName );
312         m_pImpl->aValues[ _rValueName ] = _rValue;
313         return bHas;
314     }
315 
316     //--------------------------------------------------------------------
impl_remove(const::rtl::OUString & _rValueName)317     bool NamedValueCollection::impl_remove( const ::rtl::OUString& _rValueName )
318     {
319         NamedValueRepository::iterator pos = m_pImpl->aValues.find( _rValueName );
320         if ( pos == m_pImpl->aValues.end() )
321             return false;
322         m_pImpl->aValues.erase( pos );
323         return true;
324     }
325 
326     //--------------------------------------------------------------------
327     namespace
328     {
329         struct Value2PropertyValue : public ::std::unary_function< NamedValueRepository::value_type, PropertyValue >
330         {
operator ()comphelper::__anon2b435dbe0111::Value2PropertyValue331             PropertyValue operator()( const NamedValueRepository::value_type& _rValue )
332             {
333                 return PropertyValue(
334                     _rValue.first, 0, _rValue.second, PropertyState_DIRECT_VALUE );
335             }
336         };
337 
338         struct Value2NamedValue : public ::std::unary_function< NamedValueRepository::value_type, NamedValue >
339         {
operator ()comphelper::__anon2b435dbe0111::Value2NamedValue340             NamedValue operator()( const NamedValueRepository::value_type& _rValue )
341             {
342                 return NamedValue( _rValue.first, _rValue.second );
343             }
344         };
345     }
346 
347     //--------------------------------------------------------------------
operator >>=(Sequence<PropertyValue> & _out_rValues) const348     sal_Int32 NamedValueCollection::operator >>= ( Sequence< PropertyValue >& _out_rValues ) const
349     {
350         _out_rValues.realloc( m_pImpl->aValues.size() );
351         ::std::transform( m_pImpl->aValues.begin(), m_pImpl->aValues.end(), _out_rValues.getArray(), Value2PropertyValue() );
352         return _out_rValues.getLength();
353     }
354 
355     //--------------------------------------------------------------------
operator >>=(Sequence<NamedValue> & _out_rValues) const356     sal_Int32 NamedValueCollection::operator >>= ( Sequence< NamedValue >& _out_rValues ) const
357     {
358         _out_rValues.realloc( m_pImpl->aValues.size() );
359         ::std::transform( m_pImpl->aValues.begin(), m_pImpl->aValues.end(), _out_rValues.getArray(), Value2NamedValue() );
360         return _out_rValues.getLength();
361     }
362 
363 //........................................................................
364 } // namespace comphelper
365 //........................................................................
366 
367