xref: /trunk/main/xmloff/source/style/xmlimppr.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 #include <com/sun/star/xml/AttributeData.hpp>
31 #include <com/sun/star/beans/XMultiPropertySet.hpp>
32 #include <com/sun/star/lang/IllegalArgumentException.hpp>
33 #include <com/sun/star/lang/WrappedTargetException.hpp>
34 #include <com/sun/star/beans/UnknownPropertyException.hpp>
35 #include <com/sun/star/beans/PropertyVetoException.hpp>
36 #include <com/sun/star/beans/TolerantPropertySetResultType.hpp>
37 #include <rtl/ustrbuf.hxx>
38 #include <xmloff/xmlprmap.hxx>
39 #include <xmloff/nmspmap.hxx>
40 #include <xmloff/xmlimppr.hxx>
41 #include <xmloff/xmlimp.hxx>
42 
43 #include "xmloff/unoatrcn.hxx"
44 #include "xmloff/xmlnmspe.hxx"
45 #include <xmloff/xmltoken.hxx>
46 #include "xmloff/xmlerror.hxx"
47 #include <tools/debug.hxx>
48 
49 #include "xmloff/contextid.hxx"
50 
51 // STL includes
52 #include <algorithm>
53 #include <functional>
54 #include <utility>
55 #include <vector>
56 
57 using namespace ::com::sun::star::uno;
58 using namespace ::com::sun::star::beans;
59 using namespace ::com::sun::star::container;
60 using namespace ::com::sun::star::xml;
61 using namespace ::com::sun::star::xml::sax;
62 using ::rtl::OUString;
63 using ::rtl::OUStringBuffer;
64 
65 using namespace ::std;
66 using namespace ::xmloff::token;
67 using ::com::sun::star::lang::IllegalArgumentException;
68 using ::com::sun::star::lang::WrappedTargetException;
69 using ::com::sun::star::beans::UnknownPropertyException;
70 using ::com::sun::star::beans::PropertyVetoException;
71 
72 
73 SvXMLImportPropertyMapper::SvXMLImportPropertyMapper(
74         const UniReference< XMLPropertySetMapper >& rMapper,
75         SvXMLImport& rImp ):
76     rImport(rImp),
77     maPropMapper  ( rMapper )
78 {
79 }
80 
81 SvXMLImportPropertyMapper::~SvXMLImportPropertyMapper()
82 {
83     mxNextMapper = 0;
84 }
85 
86 void SvXMLImportPropertyMapper::ChainImportMapper(
87         const UniReference< SvXMLImportPropertyMapper>& rMapper )
88 {
89     // add map entries from rMapper to current map
90     maPropMapper->AddMapperEntry( rMapper->getPropertySetMapper() );
91     // rMapper uses the same map as 'this'
92     rMapper->maPropMapper = maPropMapper;
93 
94     // set rMapper as last mapper in current chain
95     UniReference< SvXMLImportPropertyMapper > xNext = mxNextMapper;
96     if( xNext.is())
97     {
98         while( xNext->mxNextMapper.is())
99             xNext = xNext->mxNextMapper;
100         xNext->mxNextMapper = rMapper;
101     }
102     else
103         mxNextMapper = rMapper;
104 
105     // if rMapper was already chained, correct
106     // map pointer of successors
107     xNext = rMapper;
108 
109     while( xNext->mxNextMapper.is())
110     {
111         xNext = xNext->mxNextMapper;
112         xNext->maPropMapper = maPropMapper;
113     }
114 }
115 
116 void SvXMLImportPropertyMapper::importXML(
117         vector< XMLPropertyState >& rProperties,
118         Reference< XAttributeList > xAttrList,
119         const SvXMLUnitConverter& rUnitConverter,
120         const SvXMLNamespaceMap& rNamespaceMap,
121         sal_uInt32 nPropType ) const
122 {
123     importXML( rProperties, xAttrList, rUnitConverter, rNamespaceMap,
124                nPropType,-1, -1 );
125 }
126 
127 /** fills the given itemset with the attributes in the given list */
128 void SvXMLImportPropertyMapper::importXML(
129         vector< XMLPropertyState >& rProperties,
130         Reference< XAttributeList > xAttrList,
131         const SvXMLUnitConverter& rUnitConverter,
132         const SvXMLNamespaceMap& rNamespaceMap,
133         sal_uInt32 nPropType,
134         sal_Int32 nStartIdx,
135         sal_Int32 nEndIdx ) const
136 {
137     sal_Int16 nAttr = xAttrList->getLength();
138 
139     Reference< XNameContainer > xAttrContainer;
140 
141     if( -1 == nStartIdx )
142         nStartIdx = 0;
143     if( -1 == nEndIdx )
144         nEndIdx = maPropMapper->GetEntryCount();
145     for( sal_Int16 i=0; i < nAttr; i++ )
146     {
147         const OUString& rAttrName = xAttrList->getNameByIndex( i );
148         OUString aLocalName, aPrefix, aNamespace;
149         sal_uInt16 nPrefix = rNamespaceMap.GetKeyByAttrName( rAttrName, &aPrefix,
150                                                     &aLocalName, &aNamespace );
151 
152         if( XML_NAMESPACE_XMLNS == nPrefix )
153             continue;
154 
155         const OUString& rValue = xAttrList->getValueByIndex( i );
156 
157         // index of actual property map entry
158         // This looks very strange, but it works well:
159         // If the start index is 0, the new value will become -1, and
160         // GetEntryIndex will start searching with position 0.
161         // Otherwise GetEntryIndex will start with the next position specified.
162         sal_Int32 nIndex =  nStartIdx - 1;
163         sal_uInt32 nFlags = 0;  // flags of actual property map entry
164         sal_Bool bFound = sal_False;
165 
166         // for better error reporting: this should be set true if no
167         // warning is needed
168         sal_Bool bNoWarning = sal_False;
169         bool bAlienImport = false;
170 
171         do
172         {
173             // find an entry for this attribute
174             nIndex = maPropMapper->GetEntryIndex( nPrefix, aLocalName,
175                                                   nPropType, nIndex );
176 
177             if( nIndex > -1 && nIndex < nEndIdx  )
178             {
179                 // create a XMLPropertyState with an empty value
180 
181                 nFlags = maPropMapper->GetEntryFlags( nIndex );
182                 if( (( nFlags & MID_FLAG_NO_PROPERTY ) == MID_FLAG_NO_PROPERTY) && (maPropMapper->GetEntryContextId( nIndex ) == CTF_ALIEN_ATTRIBUTE_IMPORT) )
183                 {
184                     bAlienImport = true;
185                     nIndex = -1;
186                 }
187                 else
188                 {
189                     if( ( nFlags & MID_FLAG_ELEMENT_ITEM_IMPORT ) == 0 )
190                     {
191                         XMLPropertyState aNewProperty( nIndex );
192                         sal_Int32 nReference = -1;
193 
194                         // if this is a multi attribute check if another attribute already set
195                         // this any. If so use this as a initial value
196                         if( ( nFlags & MID_FLAG_MERGE_PROPERTY ) != 0 )
197                         {
198                             const OUString aAPIName( maPropMapper->GetEntryAPIName( nIndex ) );
199                             const sal_Int32 nSize = rProperties.size();
200                             for( nReference = 0; nReference < nSize; nReference++ )
201                             {
202                                 sal_Int32 nRefIdx = rProperties[nReference].mnIndex;
203                                 if( (nRefIdx != -1) && (nIndex != nRefIdx) &&
204                                     (maPropMapper->GetEntryAPIName( nRefIdx ) == aAPIName ))
205                                 {
206                                     aNewProperty = rProperties[nReference];
207                                     aNewProperty.mnIndex = nIndex;
208                                     break;
209                                 }
210                             }
211 
212                             if( nReference == nSize )
213                                 nReference = -1;
214                         }
215 
216                         sal_Bool bSet = sal_False;
217                         if( ( nFlags & MID_FLAG_SPECIAL_ITEM_IMPORT ) == 0 )
218                         {
219                             // let the XMLPropertySetMapper decide how to import the value
220                             bSet = maPropMapper->importXML( rValue, aNewProperty,
221                                                      rUnitConverter );
222                         }
223                         else
224                         {
225                             sal_uInt32 nOldSize = rProperties.size();
226 
227                             bSet = handleSpecialItem( aNewProperty, rProperties,
228                                                       rValue, rUnitConverter,
229                                                       rNamespaceMap );
230 
231                             // no warning if handleSpecialItem added properties
232                             bNoWarning |= ( nOldSize != rProperties.size() );
233                         }
234 
235                         // no warning if we found could set the item. This
236                         // 'remembers' bSet across multi properties.
237                         bNoWarning |= bSet;
238 
239                         // store the property in the given vector
240                         if( bSet )
241                         {
242                             if( nReference == -1 )
243                                 rProperties.push_back( aNewProperty );
244                             else
245                                 rProperties[nReference] = aNewProperty;
246                         }
247                         else
248                         {
249                             // warn about unknown value. Unless it's a
250                             // multi property: Then we get another chance
251                             // to set the value.
252                             if( !bNoWarning &&
253                                 ((nFlags & MID_FLAG_MULTI_PROPERTY) == 0) )
254                             {
255                                 Sequence<OUString> aSeq(2);
256                                 aSeq[0] = rAttrName;
257                                 aSeq[1] = rValue;
258                                 rImport.SetError( XMLERROR_FLAG_WARNING |
259                                                   XMLERROR_STYLE_ATTR_VALUE,
260                                                   aSeq );
261                             }
262                         }
263                     }
264                     bFound = sal_True;
265                     continue;
266                 }
267             }
268 
269             if( !bFound )
270             {
271                 if( (XML_NAMESPACE_UNKNOWN_FLAG & nPrefix) || (XML_NAMESPACE_NONE == nPrefix) || bAlienImport )
272                 {
273                     OSL_ENSURE( XML_NAMESPACE_NONE == nPrefix ||
274                                 (XML_NAMESPACE_UNKNOWN_FLAG & nPrefix) ||
275                                 bAlienImport,
276                                 "unknown attribute - might be a new feature?" );
277                     if( !xAttrContainer.is() )
278                     {
279                         // add an unknown attribute container to the properties
280                         Reference< XNameContainer > xNew( SvUnoAttributeContainer_CreateInstance(), UNO_QUERY );
281                         xAttrContainer = xNew;
282 
283                         // find map entry and create new property state
284                         if( -1 == nIndex )
285                         {
286                             switch( nPropType )
287                             {
288                                 case XML_TYPE_PROP_CHART:
289                                     nIndex = maPropMapper->FindEntryIndex( "ChartUserDefinedAttributes", XML_NAMESPACE_TEXT, GetXMLToken(XML_XMLNS) );
290                                     break;
291                                 case XML_TYPE_PROP_PARAGRAPH:
292                                     nIndex = maPropMapper->FindEntryIndex( "ParaUserDefinedAttributes", XML_NAMESPACE_TEXT, GetXMLToken(XML_XMLNS) );
293                                     break;
294                                 case  XML_TYPE_PROP_TEXT:
295                                     nIndex = maPropMapper->FindEntryIndex( "TextUserDefinedAttributes", XML_NAMESPACE_TEXT, GetXMLToken(XML_XMLNS) );
296                                     break;
297                                 default:
298                                     break;
299                             }
300                             // other property type or property not found
301                             if( -1 == nIndex )
302                                 nIndex = maPropMapper->FindEntryIndex( "UserDefinedAttributes", XML_NAMESPACE_TEXT, GetXMLToken(XML_XMLNS) );
303                         }
304 
305                         // #106963#; use userdefined attribute only if it is in the specified property range
306                         if( nIndex != -1 && nIndex >= nStartIdx && nIndex < nEndIdx)
307                         {
308                             Any aAny;
309                             aAny <<= xAttrContainer;
310                             XMLPropertyState aNewProperty( nIndex, aAny );
311 
312                             // push it on our stack so we export it later
313                             rProperties.push_back( aNewProperty );
314                         }
315                     }
316 
317                     if( xAttrContainer.is() )
318                     {
319                         AttributeData aData;
320                         aData.Type = GetXMLToken( XML_CDATA );
321                         aData.Value = rValue;
322 
323                         OUStringBuffer sName;
324                         if( XML_NAMESPACE_NONE != nPrefix )
325                         {
326                             sName.append( aPrefix );
327                             sName.append( sal_Unicode(':') );
328                             aData.Namespace = aNamespace;
329                         }
330 
331                         sName.append( aLocalName );
332 
333                         Any aAny;
334                         aAny <<= aData;
335                         xAttrContainer->insertByName( sName.makeStringAndClear(), aAny );
336                     }
337                 }
338             }
339         }
340         while( ( nIndex >= 0 ) && (( nFlags & MID_FLAG_MULTI_PROPERTY ) != 0 ) );
341     }
342 
343     finished( rProperties, nStartIdx, nEndIdx );
344 
345     // Have to do if we change from a vector to a list or something like that
346     /*std::vector <XMLPropertyState>::iterator aItr = rProperties.begin();
347     while (aItr != rProperties.end())
348     {
349         if (aItr->mnIndex == -1)
350             aItr = rProperties.erase(aItr);
351         else
352             aItr++;
353     }*/
354 }
355 
356 /** this method is called for every item that has the MID_FLAG_SPECIAL_ITEM_IMPORT flag set */
357 sal_Bool SvXMLImportPropertyMapper::handleSpecialItem(
358         XMLPropertyState& rProperty,
359         vector< XMLPropertyState >& rProperties,
360         const OUString& rValue,
361         const SvXMLUnitConverter& rUnitConverter,
362         const SvXMLNamespaceMap& rNamespaceMap ) const
363 {
364     OSL_ENSURE( mxNextMapper.is(), "unsuported special item in xml import" );
365     if( mxNextMapper.is() )
366         return mxNextMapper->handleSpecialItem( rProperty, rProperties, rValue,
367                                                rUnitConverter, rNamespaceMap );
368     else
369         return sal_False;
370 }
371 
372 void SvXMLImportPropertyMapper::FillPropertySequence(
373             const ::std::vector< XMLPropertyState >& rProperties,
374             ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rValues )
375             const
376 {
377     sal_Int32 nCount = rProperties.size();
378     sal_Int32 nValueCount = 0;
379     rValues.realloc( nCount );
380     PropertyValue *pProps = rValues.getArray();
381     for( sal_Int32 i=0; i < nCount; i++ )
382     {
383         const XMLPropertyState& rProp = rProperties[i];
384         sal_Int32 nIdx = rProp.mnIndex;
385         if( nIdx == -1 )
386             continue;
387         pProps->Name = maPropMapper->GetEntryAPIName( nIdx );
388         if( pProps->Name.getLength() )
389         {
390             pProps->Value <<= rProp.maValue;
391             ++pProps;
392             ++nValueCount;
393         }
394     }
395     if( nValueCount < nCount )
396         rValues.realloc( nValueCount );
397 }
398 
399 void SvXMLImportPropertyMapper::CheckSpecialContext(
400             const ::std::vector< XMLPropertyState >& aProperties,
401             const ::com::sun::star::uno::Reference<
402                     ::com::sun::star::beans::XPropertySet > rPropSet,
403             _ContextID_Index_Pair* pSpecialContextIds ) const
404 {
405     OSL_ENSURE( rPropSet.is(), "need an XPropertySet" );
406     sal_Int32 nCount = aProperties.size();
407 
408     Reference< XPropertySetInfo > xInfo(rPropSet->getPropertySetInfo());
409 
410     for( sal_Int32 i=0; i < nCount; i++ )
411     {
412         const XMLPropertyState& rProp = aProperties[i];
413         sal_Int32 nIdx = rProp.mnIndex;
414 
415         // disregard property state if it has an invalid index
416         if( -1 == nIdx )
417             continue;
418 
419         const sal_Int32 nPropFlags = maPropMapper->GetEntryFlags( nIdx );
420 
421         // handle no-property and special items
422         if( ( pSpecialContextIds != NULL ) &&
423             ( ( 0 != ( nPropFlags & MID_FLAG_NO_PROPERTY_IMPORT ) ) ||
424               ( 0 != ( nPropFlags & MID_FLAG_SPECIAL_ITEM_IMPORT ) )   ) )
425         {
426             // maybe it's one of our special context ids?
427             sal_Int16 nContextId = maPropMapper->GetEntryContextId(nIdx);
428 
429             for ( sal_Int32 n = 0;
430                   pSpecialContextIds[n].nContextID != -1;
431                   n++ )
432             {
433                 // found: set index in pSpecialContextIds array
434                 if ( pSpecialContextIds[n].nContextID == nContextId )
435                 {
436                     pSpecialContextIds[n].nIndex = i;
437                     break; // early out
438                 }
439             }
440         }
441     }
442 
443 }
444 
445 sal_Bool SvXMLImportPropertyMapper::FillPropertySet(
446             const vector< XMLPropertyState >& aProperties,
447             const Reference< XPropertySet > rPropSet,
448             _ContextID_Index_Pair* pSpecialContextIds ) const
449 {
450     sal_Bool bSet = sal_False;
451 
452     Reference< XTolerantMultiPropertySet > xTolPropSet( rPropSet, UNO_QUERY );
453     if (xTolPropSet.is())
454         bSet = _FillTolerantMultiPropertySet( aProperties, xTolPropSet, maPropMapper, rImport,
455                                             pSpecialContextIds );
456 
457     if (!bSet)
458     {
459         // get property set info
460         Reference< XPropertySetInfo > xInfo(rPropSet->getPropertySetInfo());
461 
462         // check for multi-property set
463         Reference<XMultiPropertySet> xMultiPropSet( rPropSet, UNO_QUERY );
464         if ( xMultiPropSet.is() )
465         {
466             // Try XMultiPropertySet. If that fails, try the regular route.
467             bSet = _FillMultiPropertySet( aProperties, xMultiPropSet,
468                                         xInfo, maPropMapper,
469                                         pSpecialContextIds );
470             if ( !bSet )
471                 bSet = _FillPropertySet( aProperties, rPropSet,
472                                         xInfo, maPropMapper, rImport,
473                                         pSpecialContextIds);
474         }
475         else
476             bSet = _FillPropertySet( aProperties, rPropSet, xInfo,
477                                     maPropMapper, rImport,
478                                     pSpecialContextIds );
479     }
480 
481     return bSet;
482 }
483 
484 sal_Bool SvXMLImportPropertyMapper::_FillPropertySet(
485     const vector<XMLPropertyState> & rProperties,
486     const Reference<XPropertySet> & rPropSet,
487     const Reference<XPropertySetInfo> & rPropSetInfo,
488     const UniReference<XMLPropertySetMapper> & rPropMapper,
489     SvXMLImport& rImport,
490     _ContextID_Index_Pair* pSpecialContextIds )
491 {
492     OSL_ENSURE( rPropSet.is(), "need an XPropertySet" );
493     OSL_ENSURE( rPropSetInfo.is(), "need an XPropertySetInfo" );
494 
495     // preliminaries
496     sal_Bool bSet = sal_False;
497     sal_Int32 nCount = rProperties.size();
498 
499     // iterate over property states that we want to set
500     for( sal_Int32 i=0; i < nCount; i++ )
501     {
502         const XMLPropertyState& rProp = rProperties[i];
503         sal_Int32 nIdx = rProp.mnIndex;
504 
505         // disregard property state if it has an invalid index
506         if( -1 == nIdx )
507             continue;
508 
509         const OUString& rPropName = rPropMapper->GetEntryAPIName( nIdx );
510         const sal_Int32 nPropFlags = rPropMapper->GetEntryFlags( nIdx );
511 
512         if ( ( 0 == ( nPropFlags & MID_FLAG_NO_PROPERTY ) ) &&
513              ( ( 0 != ( nPropFlags & MID_FLAG_MUST_EXIST ) ) ||
514                rPropSetInfo->hasPropertyByName( rPropName ) )    )
515         {
516             // try setting the property
517             try
518             {
519                 rPropSet->setPropertyValue( rPropName, rProp.maValue );
520                 bSet = sal_True;
521             }
522             catch ( IllegalArgumentException& e )
523             {
524                 // illegal value: check whether this property is
525                 // allowed to throw this exception
526                 if ( 0 == ( nPropFlags & MID_FLAG_PROPERTY_MAY_EXCEPT ) )
527                 {
528                     Sequence<OUString> aSeq(1);
529                     aSeq[0] = rPropName;
530                     rImport.SetError(
531                         XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_ERROR,
532                         aSeq, e.Message, NULL );
533                 }
534             }
535             catch ( UnknownPropertyException& e )
536             {
537                 // unknown property: This is always an error!
538                 Sequence<OUString> aSeq(1);
539                 aSeq[0] = rPropName;
540                 rImport.SetError(
541                     XMLERROR_STYLE_PROP_UNKNOWN | XMLERROR_FLAG_ERROR,
542                     aSeq, e.Message, NULL );
543             }
544             catch ( PropertyVetoException& e )
545             {
546                 // property veto: this shouldn't happen
547                 Sequence<OUString> aSeq(1);
548                 aSeq[0] = rPropName;
549                 rImport.SetError(
550                     XMLERROR_STYLE_PROP_OTHER | XMLERROR_FLAG_ERROR,
551                     aSeq, e.Message, NULL );
552             }
553             catch ( WrappedTargetException& e )
554             {
555                 // wrapped target: this shouldn't happen either
556                 Sequence<OUString> aSeq(1);
557                 aSeq[0] = rPropName;
558                 rImport.SetError(
559                     XMLERROR_STYLE_PROP_OTHER | XMLERROR_FLAG_ERROR,
560                     aSeq, e.Message, NULL );
561             }
562         }
563 
564         // handle no-property and special items
565         if( ( pSpecialContextIds != NULL ) &&
566             ( ( 0 != ( nPropFlags & MID_FLAG_NO_PROPERTY_IMPORT ) ) ||
567               ( 0 != ( nPropFlags & MID_FLAG_SPECIAL_ITEM_IMPORT ) )   ) )
568         {
569             // maybe it's one of our special context ids?
570             sal_Int16 nContextId = rPropMapper->GetEntryContextId(nIdx);
571 
572             for ( sal_Int32 n = 0;
573                   pSpecialContextIds[n].nContextID != -1;
574                   n++ )
575             {
576                 // found: set index in pSpecialContextIds array
577                 if ( pSpecialContextIds[n].nContextID == nContextId )
578                 {
579                     pSpecialContextIds[n].nIndex = i;
580                     break; // early out
581                 }
582             }
583         }
584     }
585 
586     return bSet;
587 }
588 
589 
590 
591 typedef pair<const OUString*, const Any* > PropertyPair;
592 typedef vector<PropertyPair> PropertyPairs;
593 
594 struct PropertyPairLessFunctor :
595     public binary_function<PropertyPair, PropertyPair, bool>
596 {
597     bool operator()( const PropertyPair& a, const PropertyPair& b ) const
598     {
599         return (*a.first < *b.first ? true : false);
600     }
601 };
602 
603 void SvXMLImportPropertyMapper::_PrepareForMultiPropertySet(
604     const vector<XMLPropertyState> & rProperties,
605     const Reference<XPropertySetInfo> & rPropSetInfo,
606     const UniReference<XMLPropertySetMapper> & rPropMapper,
607     _ContextID_Index_Pair* pSpecialContextIds,
608     Sequence<OUString>& rNames,
609     Sequence<Any>& rValues)
610 {
611     sal_Int32 nCount = rProperties.size();
612 
613     // property pairs structure stores names + values of properties to be set.
614     PropertyPairs aPropertyPairs;
615     aPropertyPairs.reserve( nCount );
616 
617     // iterate over property states that we want to set
618     sal_Int32 i;
619     for( i = 0; i < nCount; i++ )
620     {
621         const XMLPropertyState& rProp = rProperties[i];
622         sal_Int32 nIdx = rProp.mnIndex;
623 
624         // disregard property state if it has an invalid index
625         if( -1 == nIdx )
626             continue;
627 
628         const OUString& rPropName = rPropMapper->GetEntryAPIName( nIdx );
629         const sal_Int32 nPropFlags = rPropMapper->GetEntryFlags( nIdx );
630 
631         if ( ( 0 == ( nPropFlags & MID_FLAG_NO_PROPERTY ) ) &&
632              ( ( 0 != ( nPropFlags & MID_FLAG_MUST_EXIST ) ) ||
633                !rPropSetInfo.is() ||
634                (rPropSetInfo.is() && rPropSetInfo->hasPropertyByName( rPropName )) ) )
635         {
636             // save property into property pair structure
637             aPropertyPairs.push_back( PropertyPair( &rPropName, &rProp.maValue ) );
638         }
639 
640         // handle no-property and special items
641         if( ( pSpecialContextIds != NULL ) &&
642             ( ( 0 != ( nPropFlags & MID_FLAG_NO_PROPERTY_IMPORT ) ) ||
643               ( 0 != ( nPropFlags & MID_FLAG_SPECIAL_ITEM_IMPORT ) )   ) )
644         {
645             // maybe it's one of our special context ids?
646             sal_Int16 nContextId = rPropMapper->GetEntryContextId(nIdx);
647             for ( sal_Int32 n = 0;
648                   pSpecialContextIds[n].nContextID != -1;
649                   n++ )
650             {
651                 // found: set index in pSpecialContextIds array
652                 if ( pSpecialContextIds[n].nContextID == nContextId )
653                 {
654                     pSpecialContextIds[n].nIndex = i;
655                     break; // early out
656                 }
657             }
658         }
659     }
660 
661     // We now need to construct the sequences and actually the set
662     // values.
663 
664     // sort the property pairs
665     sort( aPropertyPairs.begin(), aPropertyPairs.end(),
666           PropertyPairLessFunctor());
667 
668     // create sequences
669     rNames.realloc( aPropertyPairs.size() );
670     OUString* pNamesArray = rNames.getArray();
671     rValues.realloc( aPropertyPairs.size() );
672     Any* pValuesArray = rValues.getArray();
673 
674     // copy values into sequences
675     i = 0;
676     for( PropertyPairs::iterator aIter = aPropertyPairs.begin();
677          aIter != aPropertyPairs.end();
678          ++aIter )
679     {
680         pNamesArray[i] = *(aIter->first);
681         pValuesArray[i++] = *(aIter->second);
682     }
683 }
684 
685 sal_Bool SvXMLImportPropertyMapper::_FillMultiPropertySet(
686     const vector<XMLPropertyState> & rProperties,
687     const Reference<XMultiPropertySet> & rMultiPropSet,
688     const Reference<XPropertySetInfo> & rPropSetInfo,
689     const UniReference<XMLPropertySetMapper> & rPropMapper,
690     _ContextID_Index_Pair* pSpecialContextIds )
691 {
692     OSL_ENSURE( rMultiPropSet.is(), "Need multi property set. ");
693     OSL_ENSURE( rPropSetInfo.is(), "Need property set info." );
694 
695     sal_Bool bSuccessful = sal_False;
696 
697     Sequence<OUString> aNames;
698     Sequence<Any> aValues;
699 
700     _PrepareForMultiPropertySet(rProperties, rPropSetInfo, rPropMapper, pSpecialContextIds,
701         aNames, aValues);
702 
703     // and, finally, try to set the values
704     try
705     {
706         rMultiPropSet->setPropertyValues( aNames, aValues );
707         bSuccessful = sal_True;
708     }
709     catch ( ... )
710     {
711         OSL_ENSURE(bSuccessful, "Exception caught; style may not be imported correctly.");
712     }
713 
714     return bSuccessful;
715 }
716 
717 sal_Bool SvXMLImportPropertyMapper::_FillTolerantMultiPropertySet(
718     const vector<XMLPropertyState> & rProperties,
719     const Reference<XTolerantMultiPropertySet> & rTolMultiPropSet,
720     const UniReference<XMLPropertySetMapper> & rPropMapper,
721     SvXMLImport& rImport,
722     _ContextID_Index_Pair* pSpecialContextIds )
723 {
724     OSL_ENSURE( rTolMultiPropSet.is(), "Need tolerant multi property set. ");
725 
726     sal_Bool bSuccessful = sal_False;
727 
728     Sequence<OUString> aNames;
729     Sequence<Any> aValues;
730 
731     _PrepareForMultiPropertySet(rProperties, Reference<XPropertySetInfo>(NULL), rPropMapper, pSpecialContextIds,
732         aNames, aValues);
733 
734     // and, finally, try to set the values
735     try
736     {
737         Sequence< SetPropertyTolerantFailed > aResults(rTolMultiPropSet->setPropertyValuesTolerant( aNames, aValues ));
738         if (aResults.getLength() == 0)
739             bSuccessful = sal_True;
740         else
741         {
742             sal_Int32 nCount(aResults.getLength());
743             for( sal_Int32 i = 0; i < nCount; ++i)
744             {
745                 Sequence<OUString> aSeq(1);
746                 aSeq[0] = aResults[i].Name;
747                 rtl::OUString sMessage;
748                 switch (aResults[i].Result)
749                 {
750                 case TolerantPropertySetResultType::UNKNOWN_PROPERTY :
751                     sMessage = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("UNKNOWN_PROPERTY"));
752                     break;
753                 case TolerantPropertySetResultType::ILLEGAL_ARGUMENT :
754                     sMessage = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ILLEGAL_ARGUMENT"));
755                     break;
756                 case TolerantPropertySetResultType::PROPERTY_VETO :
757                     sMessage = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("PROPERTY_VETO"));
758                     break;
759                 case TolerantPropertySetResultType::WRAPPED_TARGET :
760                     sMessage = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("WRAPPED_TARGET"));
761                     break;
762                 };
763                 rImport.SetError(
764                     XMLERROR_STYLE_PROP_OTHER | XMLERROR_FLAG_ERROR,
765                     aSeq, sMessage, NULL );
766             }
767         }
768     }
769     catch ( ... )
770     {
771         OSL_ENSURE(bSuccessful, "Exception caught; style may not be imported correctly.");
772     }
773 
774     return bSuccessful;
775 }
776 
777 void SvXMLImportPropertyMapper::finished(
778         vector< XMLPropertyState >& rProperties,
779         sal_Int32 nStartIndex, sal_Int32 nEndIndex ) const
780 {
781     // nothing to do here
782     if( mxNextMapper.is() )
783         mxNextMapper->finished( rProperties, nStartIndex, nEndIndex );
784 }
785