xref: /AOO41X/main/xmloff/source/style/xmlimppr.cxx (revision 63bba73cc51e0afb45f8a8d578158724bb5afee8)
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 ) && (( 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