xref: /aoo41x/main/xmloff/source/style/xmlimppr.cxx (revision cdf0e10c)
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