xref: /AOO41X/main/comphelper/source/property/propertycontainerhelper.cxx (revision dde7d3faf6dcd9cbeb7b48ba6d0cea5ffcc883d0)
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/propertycontainerhelper.hxx>
27 #include <comphelper/property.hxx>
28 #include <osl/diagnose.h>
29 #include <uno/data.h>
30 #include <com/sun/star/uno/genfunc.h>
31 #include <com/sun/star/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/beans/UnknownPropertyException.hpp>
33 #include <rtl/ustrbuf.hxx>
34 
35 #include <algorithm>
36 
37 //.........................................................................
38 namespace comphelper
39 {
40 //.........................................................................
41 
42 using namespace ::com::sun::star::uno;
43 using namespace ::com::sun::star::lang;
44 using namespace ::com::sun::star::beans;
45 
46 //--------------------------------------------------------------------------
47 namespace
48 {
49     // comparing two property descriptions
50     struct PropertyDescriptionCompareByHandle : public ::std::binary_function< PropertyDescription, PropertyDescription, bool >
51     {
operator ()comphelper::__anonc6e9f6d90111::PropertyDescriptionCompareByHandle52         bool operator() (const PropertyDescription& x, const PropertyDescription& y) const
53         {
54             return x.aProperty.Handle < y.aProperty.Handle;
55         }
56     };
57     // comparing two property descriptions
58     struct PropertyDescriptionHandleCompare : public ::std::binary_function< PropertyDescription, sal_Int32, bool >
59     {
operator ()comphelper::__anonc6e9f6d90111::PropertyDescriptionHandleCompare60         bool operator() (const PropertyDescription& x, const sal_Int32& y) const
61         {
62             return x.aProperty.Handle < y;
63         }
operator ()comphelper::__anonc6e9f6d90111::PropertyDescriptionHandleCompare64         bool operator() (const sal_Int32& x, const PropertyDescription& y) const
65         {
66             return x < y.aProperty.Handle;
67         }
68     };
69     // comparing two property descriptions (by name)
70     struct PropertyDescriptionNameMatch : public ::std::unary_function< PropertyDescription, bool >
71     {
72         ::rtl::OUString m_rCompare;
PropertyDescriptionNameMatchcomphelper::__anonc6e9f6d90111::PropertyDescriptionNameMatch73         PropertyDescriptionNameMatch( const ::rtl::OUString& _rCompare ) : m_rCompare( _rCompare ) { }
74 
operator ()comphelper::__anonc6e9f6d90111::PropertyDescriptionNameMatch75         bool operator() (const PropertyDescription& x ) const
76         {
77             return x.aProperty.Name.equals(m_rCompare);
78         }
79     };
80 }
81 
82 //==========================================================================
83 //= OPropertyContainerHelper
84 //==========================================================================
85 //--------------------------------------------------------------------------
OPropertyContainerHelper()86 OPropertyContainerHelper::OPropertyContainerHelper()
87     :m_bUnused(sal_False)
88 {
89 }
90 
91 // -------------------------------------------------------------------------
~OPropertyContainerHelper()92 OPropertyContainerHelper::~OPropertyContainerHelper()
93 {
94 }
95 
96 //--------------------------------------------------------------------------
registerProperty(const::rtl::OUString & _rName,sal_Int32 _nHandle,sal_Int32 _nAttributes,void * _pPointerToMember,const Type & _rMemberType)97 void OPropertyContainerHelper::registerProperty(const ::rtl::OUString& _rName, sal_Int32 _nHandle,
98         sal_Int32 _nAttributes, void* _pPointerToMember, const Type& _rMemberType)
99 {
100     OSL_ENSURE((_nAttributes & PropertyAttribute::MAYBEVOID) == 0,
101         "OPropertyContainerHelper::registerProperty: don't use this for properties which may be void ! There is a method called \"registerMayBeVoidProperty\" for this !");
102     OSL_ENSURE(!_rMemberType.equals(::getCppuType(static_cast< Any* >(NULL))),
103         "OPropertyContainerHelper::registerProperty: don't give my the type of an uno::Any ! Really can't handle this !");
104     OSL_ENSURE(_pPointerToMember,
105         "OPropertyContainerHelper::registerProperty: you gave me nonsense : the pointer must be non-NULL");
106 
107     PropertyDescription aNewProp;
108     aNewProp.aProperty = Property( _rName, _nHandle, _rMemberType, (sal_Int16)_nAttributes );
109     aNewProp.eLocated = PropertyDescription::ltDerivedClassRealType;
110     aNewProp.aLocation.pDerivedClassMember = _pPointerToMember;
111 
112     implPushBackProperty(aNewProp);
113 }
114 
115 //--------------------------------------------------------------------------
revokeProperty(sal_Int32 _nHandle)116 void OPropertyContainerHelper::revokeProperty( sal_Int32 _nHandle )
117 {
118     PropertiesIterator aPos = searchHandle( _nHandle );
119     if ( aPos == m_aProperties.end() )
120         throw UnknownPropertyException();
121     m_aProperties.erase( aPos );
122 }
123 
124 //--------------------------------------------------------------------------
registerMayBeVoidProperty(const::rtl::OUString & _rName,sal_Int32 _nHandle,sal_Int32 _nAttributes,Any * _pPointerToMember,const Type & _rExpectedType)125 void OPropertyContainerHelper::registerMayBeVoidProperty(const ::rtl::OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes,
126         Any* _pPointerToMember, const Type& _rExpectedType)
127 {
128     OSL_ENSURE((_nAttributes & PropertyAttribute::MAYBEVOID) != 0,
129         "OPropertyContainerHelper::registerMayBeVoidProperty: why calling this when the attributes say nothing about may-be-void ?");
130     OSL_ENSURE(!_rExpectedType.equals(::getCppuType(static_cast< Any* >(NULL))),
131         "OPropertyContainerHelper::registerMayBeVoidProperty: don't give my the type of an uno::Any ! Really can't handle this !");
132     OSL_ENSURE(_pPointerToMember,
133         "OPropertyContainerHelper::registerMayBeVoidProperty: you gave me nonsense : the pointer must be non-NULL");
134 
135     _nAttributes |= PropertyAttribute::MAYBEVOID;
136 
137     PropertyDescription aNewProp;
138     aNewProp.aProperty = Property( _rName, _nHandle, _rExpectedType, (sal_Int16)_nAttributes );
139     aNewProp.eLocated = PropertyDescription::ltDerivedClassAnyType;
140     aNewProp.aLocation.pDerivedClassMember = _pPointerToMember;
141 
142     implPushBackProperty(aNewProp);
143 }
144 
145 
146 //--------------------------------------------------------------------------
registerPropertyNoMember(const::rtl::OUString & _rName,sal_Int32 _nHandle,sal_Int32 _nAttributes,const Type & _rType,const void * _pInitialValue)147 void OPropertyContainerHelper::registerPropertyNoMember(const ::rtl::OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes,
148         const Type& _rType, const void* _pInitialValue)
149 {
150     OSL_ENSURE(!_rType.equals(::getCppuType(static_cast< Any* >(NULL))),
151         "OPropertyContainerHelper::registerPropertyNoMember : don't give my the type of an uno::Any ! Really can't handle this !");
152     OSL_ENSURE(_pInitialValue || ((_nAttributes & PropertyAttribute::MAYBEVOID) != 0),
153         "OPropertyContainerHelper::registerPropertyNoMember : you should not ommit the initial value if the property can't be void ! This will definitivly crash later !");
154 
155     PropertyDescription aNewProp;
156     aNewProp.aProperty = Property( _rName, _nHandle, _rType, (sal_Int16)_nAttributes );
157     aNewProp.eLocated = PropertyDescription::ltHoldMyself;
158     aNewProp.aLocation.nOwnClassVectorIndex = m_aHoldProperties.size();
159     if (_pInitialValue)
160         m_aHoldProperties.push_back(Any(_pInitialValue, _rType));
161     else
162         m_aHoldProperties.push_back(Any());
163 
164     implPushBackProperty(aNewProp);
165 }
166 
167 //--------------------------------------------------------------------------
isRegisteredProperty(sal_Int32 _nHandle) const168 sal_Bool OPropertyContainerHelper::isRegisteredProperty( sal_Int32 _nHandle ) const
169 {
170     return const_cast< OPropertyContainerHelper* >( this )->searchHandle( _nHandle ) != m_aProperties.end();
171 }
172 
173 //--------------------------------------------------------------------------
isRegisteredProperty(const::rtl::OUString & _rName) const174 sal_Bool OPropertyContainerHelper::isRegisteredProperty( const ::rtl::OUString& _rName ) const
175 {
176     // TODO: the current structure is from a time where properties were
177     // static, not dynamic. Since we allow that properties are also dynamic,
178     // i.e. registered and revoked even though the XPropertySet has already been
179     // accessed, a vector is not really the best data structure anymore ...
180 
181     ConstPropertiesIterator pos = ::std::find_if(
182         m_aProperties.begin(),
183         m_aProperties.end(),
184         PropertyDescriptionNameMatch( _rName )
185     );
186     return pos != m_aProperties.end();
187 }
188 
189 //--------------------------------------------------------------------------
190 namespace
191 {
192     struct ComparePropertyWithHandle
193     {
operator ()comphelper::__anonc6e9f6d90211::ComparePropertyWithHandle194         bool operator()( const PropertyDescription& _rLHS, sal_Int32 _nRHS ) const
195         {
196             return _rLHS.aProperty.Handle < _nRHS;
197         }
operator ()comphelper::__anonc6e9f6d90211::ComparePropertyWithHandle198         bool operator()( sal_Int32 _nLHS, const PropertyDescription& _rRHS ) const
199         {
200             return _nLHS < _rRHS.aProperty.Handle;
201         }
202     };
203 }
204 
205 //--------------------------------------------------------------------------
implPushBackProperty(const PropertyDescription & _rProp)206 void OPropertyContainerHelper::implPushBackProperty(const PropertyDescription& _rProp)
207 {
208 #ifdef DBG_UTIL
209     for (   PropertiesIterator checkConflicts = m_aProperties.begin();
210             checkConflicts != m_aProperties.end();
211             ++checkConflicts
212         )
213     {
214         OSL_ENSURE(checkConflicts->aProperty.Name != _rProp.aProperty.Name, "OPropertyContainerHelper::implPushBackProperty: name already exists!");
215         OSL_ENSURE(checkConflicts->aProperty.Handle != _rProp.aProperty.Handle, "OPropertyContainerHelper::implPushBackProperty: handle already exists!");
216     }
217 #endif
218 
219     PropertiesIterator pos = ::std::lower_bound(
220         m_aProperties.begin(), m_aProperties.end(),
221         _rProp.aProperty.Handle, ComparePropertyWithHandle() );
222 
223     m_aProperties.insert( pos, _rProp );
224 }
225 
226 //--------------------------------------------------------------------------
227 namespace
228 {
lcl_throwIllegalPropertyValueTypeException(const PropertyDescription & _rProperty,const Any & _rValue)229     void lcl_throwIllegalPropertyValueTypeException( const PropertyDescription& _rProperty, const Any& _rValue )
230     {
231         ::rtl::OUStringBuffer aErrorMessage;
232         aErrorMessage.appendAscii( "The given value cannot be converted to the required property type." );
233         aErrorMessage.appendAscii( "\n(property name \"" );
234         aErrorMessage.append( _rProperty.aProperty.Name );
235         aErrorMessage.appendAscii( "\", found value type \"" );
236         aErrorMessage.append( _rValue.getValueType().getTypeName() );
237         aErrorMessage.appendAscii( "\", required property type \"" );
238         aErrorMessage.append( _rProperty.aProperty.Type.getTypeName() );
239         aErrorMessage.appendAscii( "\")" );
240         throw IllegalArgumentException( aErrorMessage.makeStringAndClear(), NULL, 4 );
241     }
242 }
243 
244 //--------------------------------------------------------------------------
convertFastPropertyValue(Any & _rConvertedValue,Any & _rOldValue,sal_Int32 _nHandle,const Any & _rValue)245 sal_Bool OPropertyContainerHelper::convertFastPropertyValue(
246     Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) SAL_THROW( (IllegalArgumentException) )
247 {
248     sal_Bool bModified = sal_False;
249 
250     // get the property somebody is asking for
251     PropertiesIterator aPos = searchHandle(_nHandle);
252     if (aPos == m_aProperties.end())
253     {
254         OSL_ENSURE( false, "OPropertyContainerHelper::convertFastPropertyValue: unknown handle!" );
255         // should not happen if the derived class has built a correct property set info helper to be used by
256         // our base class OPropertySetHelper
257         return bModified;
258     }
259 
260     switch (aPos->eLocated)
261     {
262         // similar handling for the two cases where the value is stored in an any
263         case PropertyDescription::ltHoldMyself:
264         case PropertyDescription::ltDerivedClassAnyType:
265         {
266             sal_Bool bMayBeVoid = ((aPos->aProperty.Attributes & PropertyAttribute::MAYBEVOID) != 0);
267 
268 
269             // non modifiable version of the value-to-be-set
270             Any aNewRequestedValue( _rValue );
271 
272             // normalization
273             // (#102329# - 2002-08-14 - fs@openoffice.org)
274             // (#i29490# - 2004-06-16 - fs@openoffice.org)
275             if ( !aNewRequestedValue.getValueType().equals( aPos->aProperty.Type ) )
276             {   // the actually given value is not of the same type as the one required
277                 Any aProperlyTyped( NULL, aPos->aProperty.Type.getTypeLibType() );
278 
279                 if (    uno_type_assignData(
280                             const_cast< void* >( aProperlyTyped.getValue() ), aProperlyTyped.getValueType().getTypeLibType(),
281                             const_cast< void* >( aNewRequestedValue.getValue() ), aNewRequestedValue.getValueType().getTypeLibType(),
282                             reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
283                             reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
284                             reinterpret_cast< uno_ReleaseFunc >( cpp_release )
285                         )
286                     )
287                 {
288                     // we were able to query the given XInterface-derivee for the interface
289                     // which is required for this property
290                     aNewRequestedValue = aProperlyTyped;
291                 }
292             }
293 
294             // argument check
295             if  (   !   (   (bMayBeVoid && !aNewRequestedValue.hasValue())                      // void is allowed if the attribute says so
296                         ||  (aNewRequestedValue.getValueType().equals(aPos->aProperty.Type))    // else the types have to be equal
297                         )
298                 )
299             {
300                 lcl_throwIllegalPropertyValueTypeException( *aPos, _rValue );
301             }
302 
303             Any* pPropContainer = NULL;
304                 // the pointer to the any which holds the property value, no matter if located in the derived clas
305                 // or in out vector
306 
307             if (PropertyDescription::ltHoldMyself == aPos->eLocated)
308             {
309                 OSL_ENSURE(aPos->aLocation.nOwnClassVectorIndex < (sal_Int32)m_aHoldProperties.size(),
310                     "OPropertyContainerHelper::convertFastPropertyValue: invalid position !");
311                 PropertyContainerIterator aIter = m_aHoldProperties.begin() + aPos->aLocation.nOwnClassVectorIndex;
312                 pPropContainer = &(*aIter);
313             }
314             else
315                 pPropContainer = reinterpret_cast<Any*>(aPos->aLocation.pDerivedClassMember);
316 
317             // check if the new value differs from the current one
318             if (!pPropContainer->hasValue() || !aNewRequestedValue.hasValue())
319                 bModified = pPropContainer->hasValue() != aNewRequestedValue.hasValue();
320             else
321                 bModified = !uno_type_equalData(
322                                 const_cast< void* >( pPropContainer->getValue() ), aPos->aProperty.Type.getTypeLibType(),
323                                 const_cast< void* >( aNewRequestedValue.getValue() ), aPos->aProperty.Type.getTypeLibType(),
324                                 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
325                                 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
326                             );
327 
328             if (bModified)
329             {
330                 _rOldValue = *pPropContainer;
331                 _rConvertedValue = aNewRequestedValue;
332             }
333         }
334         break;
335         case PropertyDescription::ltDerivedClassRealType:
336             // let the UNO runtime library do any possible conversion
337             // this may include a change of the type - for instance, if a LONG is required,
338             // but a short is given, then this is valid, as it can be converted without any potential
339             // data loss
340 
341             Any aProperlyTyped;
342             const Any* pNewValue = &_rValue;
343 
344             if (!_rValue.getValueType().equals(aPos->aProperty.Type))
345             {
346                 sal_Bool bConverted = sal_False;
347 
348                 // a temporary any of the correct (required) type
349                 aProperlyTyped = Any( NULL, aPos->aProperty.Type.getTypeLibType() );
350                     // (need this as we do not want to overwrite the derived class member here)
351 
352                 if (    uno_type_assignData(
353                             const_cast<void*>(aProperlyTyped.getValue()), aProperlyTyped.getValueType().getTypeLibType(),
354                             const_cast<void*>(_rValue.getValue()), _rValue.getValueType().getTypeLibType(),
355                             reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
356                             reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
357                             reinterpret_cast< uno_ReleaseFunc >( cpp_release )
358                         )
359                     )
360                 {
361                     // could query for the requested interface
362                     bConverted = sal_True;
363                     pNewValue = &aProperlyTyped;
364                 }
365 
366                 if ( !bConverted )
367                     lcl_throwIllegalPropertyValueTypeException( *aPos, _rValue );
368             }
369 
370             // from here on, we should have the proper type
371             OSL_ENSURE( pNewValue->getValueType() == aPos->aProperty.Type,
372                 "OPropertyContainerHelper::convertFastPropertyValue: conversion failed!" );
373             bModified = !uno_type_equalData(
374                             aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type.getTypeLibType(),
375                             const_cast<void*>(pNewValue->getValue()), aPos->aProperty.Type.getTypeLibType(),
376                             reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
377                             reinterpret_cast< uno_ReleaseFunc >( cpp_release )
378                         );
379 
380             if (bModified)
381             {
382                 _rOldValue.setValue(aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type);
383                 _rConvertedValue = *pNewValue;
384             }
385             break;
386     }
387 
388     return bModified;
389 }
390 
391 //--------------------------------------------------------------------------
setFastPropertyValue(sal_Int32 _nHandle,const Any & _rValue)392 void OPropertyContainerHelper::setFastPropertyValue(sal_Int32 _nHandle, const Any& _rValue) SAL_THROW( (Exception) )
393 {
394     // get the property somebody is asking for
395     PropertiesIterator aPos = searchHandle(_nHandle);
396     if (aPos == m_aProperties.end())
397     {
398         OSL_ENSURE( false, "OPropertyContainerHelper::setFastPropertyValue: unknown handle!" );
399         // should not happen if the derived class has built a correct property set info helper to be used by
400         // our base class OPropertySetHelper
401         return;
402     }
403 
404     switch (aPos->eLocated)
405     {
406         case PropertyDescription::ltHoldMyself:
407             m_aHoldProperties[aPos->aLocation.nOwnClassVectorIndex] = _rValue;
408             break;
409 
410         case PropertyDescription::ltDerivedClassAnyType:
411             *reinterpret_cast< Any* >(aPos->aLocation.pDerivedClassMember) = _rValue;
412             break;
413 
414         case PropertyDescription::ltDerivedClassRealType:
415 #if OSL_DEBUG_LEVEL > 0
416             sal_Bool bSuccess =
417 #endif
418             // copy the data from the to-be-set value
419             uno_type_assignData(
420                 aPos->aLocation.pDerivedClassMember,        aPos->aProperty.Type.getTypeLibType(),
421                 const_cast< void* >( _rValue.getValue() ),  _rValue.getValueType().getTypeLibType(),
422                 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
423                 reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
424                 reinterpret_cast< uno_ReleaseFunc >( cpp_release ) );
425 
426             OSL_ENSURE( bSuccess,
427                 "OPropertyContainerHelper::setFastPropertyValue: ooops .... the value could not be assigned!");
428 
429             break;
430     }
431 }
432 
433 //--------------------------------------------------------------------------
getFastPropertyValue(Any & _rValue,sal_Int32 _nHandle) const434 void OPropertyContainerHelper::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
435 {
436     // get the property somebody is asking for
437     PropertiesIterator aPos = const_cast<OPropertyContainerHelper*>(this)->searchHandle(_nHandle);
438     if (aPos == m_aProperties.end())
439     {
440         OSL_ENSURE( false, "OPropertyContainerHelper::getFastPropertyValue: unknown handle!" );
441         // should not happen if the derived class has built a correct property set info helper to be used by
442         // our base class OPropertySetHelper
443         return;
444     }
445 
446     switch (aPos->eLocated)
447     {
448         case PropertyDescription::ltHoldMyself:
449             OSL_ENSURE(aPos->aLocation.nOwnClassVectorIndex < (sal_Int32)m_aHoldProperties.size(),
450                 "OPropertyContainerHelper::convertFastPropertyValue: invalid position !");
451             _rValue = m_aHoldProperties[aPos->aLocation.nOwnClassVectorIndex];
452             break;
453         case PropertyDescription::ltDerivedClassAnyType:
454             _rValue = *reinterpret_cast<Any*>(aPos->aLocation.pDerivedClassMember);
455             break;
456         case PropertyDescription::ltDerivedClassRealType:
457             _rValue.setValue(aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type);
458             break;
459     }
460 }
461 
462 //--------------------------------------------------------------------------
searchHandle(sal_Int32 _nHandle)463 OPropertyContainerHelper::PropertiesIterator OPropertyContainerHelper::searchHandle(sal_Int32 _nHandle)
464 {
465     // search a lower bound
466     PropertiesIterator aLowerBound = ::std::lower_bound(
467         m_aProperties.begin(),
468         m_aProperties.end(),
469         _nHandle,
470         PropertyDescriptionHandleCompare());
471 
472     // check for identity
473     if ((aLowerBound != m_aProperties.end()) && aLowerBound->aProperty.Handle != _nHandle)
474         aLowerBound = m_aProperties.end();
475 
476     return aLowerBound;
477 }
478 
479 //--------------------------------------------------------------------------
getProperty(const::rtl::OUString & _rName) const480 const Property& OPropertyContainerHelper::getProperty( const ::rtl::OUString& _rName ) const
481 {
482     ConstPropertiesIterator pos = ::std::find_if(
483         m_aProperties.begin(),
484         m_aProperties.end(),
485         PropertyDescriptionNameMatch( _rName )
486     );
487     if ( pos == m_aProperties.end() )
488         throw UnknownPropertyException( _rName, NULL );
489 
490     return pos->aProperty;
491 }
492 
493 //--------------------------------------------------------------------------
modifyAttributes(sal_Int32 _nHandle,sal_Int32 _nAddAttrib,sal_Int32 _nRemoveAttrib)494 void OPropertyContainerHelper::modifyAttributes(sal_Int32 _nHandle, sal_Int32 _nAddAttrib, sal_Int32 _nRemoveAttrib)
495 {
496     // get the property somebody is asking for
497     PropertiesIterator aPos = searchHandle(_nHandle);
498     if (aPos == m_aProperties.end())
499     {
500         OSL_ENSURE( false, "OPropertyContainerHelper::modifyAttributes: unknown handle!" );
501         // should not happen if the derived class has built a correct property set info helper to be used by
502         // our base class OPropertySetHelper
503         return;
504     }
505     aPos->aProperty.Handle |= _nAddAttrib;
506     aPos->aProperty.Handle &= ~_nRemoveAttrib;
507 }
508 
509 //--------------------------------------------------------------------------
describeProperties(Sequence<Property> & _rProps) const510 void OPropertyContainerHelper::describeProperties(Sequence< Property >& _rProps) const
511 {
512     Sequence< Property > aOwnProps(m_aProperties.size());
513     Property* pOwnProps = aOwnProps.getArray();
514 
515     for (   ConstPropertiesIterator aLoop = m_aProperties.begin();
516             aLoop != m_aProperties.end();
517             ++aLoop, ++pOwnProps
518         )
519     {
520         pOwnProps->Name = aLoop->aProperty.Name;
521         pOwnProps->Handle = aLoop->aProperty.Handle;
522         pOwnProps->Attributes = (sal_Int16)aLoop->aProperty.Attributes;
523         pOwnProps->Type = aLoop->aProperty.Type;
524     }
525 
526     // as our property vector is sorted by handles, not by name, we have to sort aOwnProps
527     ::std::sort(aOwnProps.getArray(), aOwnProps.getArray() + aOwnProps.getLength(), PropertyCompareByName());
528 
529     // unfortunally the STL merge function does not allow the output range to overlap one of the input ranges,
530     // so we need an extra sequence
531     Sequence< Property > aOutput;
532     aOutput.realloc(_rProps.getLength() + aOwnProps.getLength());
533     // do the merge
534     ::std::merge(   _rProps.getConstArray(), _rProps.getConstArray() + _rProps.getLength(),         // input 1
535                     aOwnProps.getConstArray(), aOwnProps.getConstArray() + aOwnProps.getLength(),   // input 2
536                     aOutput.getArray(),                                                             // output
537                     PropertyCompareByName()                                                         // compare operator
538                 );
539 
540     // copy the output
541     _rProps = aOutput;
542 }
543 
544 //.........................................................................
545 }   // namespace comphelper
546 //.........................................................................
547 
548 
549