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