1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <string_view>
23 #include <com/sun/star/container/XNameContainer.hpp>
24 #include <com/sun/star/xml/AttributeData.hpp>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/beans/XPropertyState.hpp>
27 #include <com/sun/star/beans/XMultiPropertySet.hpp>
28 #include <com/sun/star/beans/XTolerantMultiPropertySet.hpp>
29 #include <com/sun/star/beans/TolerantPropertySetResultType.hpp>
30 #include <rtl/ustrbuf.hxx>
31 #include <comphelper/anycompare.hxx>
32 #include <comphelper/diagnose_ex.hxx>
33 #include <cppuhelper/weakref.hxx>
34 #include <osl/diagnose.h>
37 #include <o3tl/sorted_vector.hxx>
40 #include <xmloff/xmlexppr.hxx>
41 #include <xmloff/xmltoken.hxx>
42 #include <xmloff/namespacemap.hxx>
43 #include <xmloff/xmlnamespace.hxx>
44 #include <xmloff/xmlexp.hxx>
45 #include <xmloff/xmlprmap.hxx>
46 #include <xmloff/maptype.hxx>
47 #include <xmloff/xmltypes.hxx>
48 #include <xmloff/xmlprhdl.hxx>
50 using namespace ::com::sun::star
;
51 using namespace ::com::sun::star::beans
;
52 using namespace ::com::sun::star::uno
;
53 using namespace ::com::sun::star::lang
;
54 using namespace ::xmloff::token
;
56 #define GET_PROP_TYPE( f ) static_cast<sal_uInt16>((f & XML_TYPE_PROP_MASK) >> XML_TYPE_PROP_SHIFT)
60 struct XMLPropTokens_Impl
66 const sal_uInt16 MAX_PROP_TYPES
=
67 (XML_TYPE_PROP_END
>> XML_TYPE_PROP_SHIFT
) -
68 (XML_TYPE_PROP_START
>> XML_TYPE_PROP_SHIFT
);
70 XMLPropTokens_Impl
const aPropTokens
[MAX_PROP_TYPES
] =
72 { GET_PROP_TYPE(XML_TYPE_PROP_CHART
), XML_CHART_PROPERTIES
},
73 { GET_PROP_TYPE(XML_TYPE_PROP_GRAPHIC
), XML_GRAPHIC_PROPERTIES
},
74 { GET_PROP_TYPE(XML_TYPE_PROP_TABLE
), XML_TABLE_PROPERTIES
},
75 { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_COLUMN
), XML_TABLE_COLUMN_PROPERTIES
},
76 { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_ROW
), XML_TABLE_ROW_PROPERTIES
},
77 { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_CELL
), XML_TABLE_CELL_PROPERTIES
},
78 { GET_PROP_TYPE(XML_TYPE_PROP_LIST_LEVEL
), XML_LIST_LEVEL_PROPERTIES
},
79 { GET_PROP_TYPE(XML_TYPE_PROP_PARAGRAPH
), XML_PARAGRAPH_PROPERTIES
},
80 { GET_PROP_TYPE(XML_TYPE_PROP_TEXT
), XML_TEXT_PROPERTIES
},
81 { GET_PROP_TYPE(XML_TYPE_PROP_DRAWING_PAGE
), XML_DRAWING_PAGE_PROPERTIES
},
82 { GET_PROP_TYPE(XML_TYPE_PROP_PAGE_LAYOUT
), XML_PAGE_LAYOUT_PROPERTIES
},
83 { GET_PROP_TYPE(XML_TYPE_PROP_HEADER_FOOTER
), XML_HEADER_FOOTER_PROPERTIES
},
84 { GET_PROP_TYPE(XML_TYPE_PROP_RUBY
), XML_RUBY_PROPERTIES
},
85 { GET_PROP_TYPE(XML_TYPE_PROP_SECTION
), XML_SECTION_PROPERTIES
}
90 // Take all properties of the XPropertySet which are also found in the
91 // XMLPropertyMapEntry-array and which are not set to their default-value,
92 // if a state is available.
93 // After that I call the method 'ContextFilter'.
95 struct ComparePropertyState
97 bool operator()(XMLPropertyState
const& lhs
, XMLPropertyState
const& rhs
)
99 return lhs
.mnIndex
< rhs
.mnIndex
;
102 class XMLPropertyStates_Impl
104 o3tl::sorted_vector
<XMLPropertyState
, ComparePropertyState
> aPropStates
;
106 XMLPropertyStates_Impl();
107 void AddPropertyState(const XMLPropertyState
& rPropState
);
108 void FillPropertyStateVector(std::vector
<XMLPropertyState
>& rVector
);
111 XMLPropertyStates_Impl::XMLPropertyStates_Impl()
115 void XMLPropertyStates_Impl::AddPropertyState(
116 const XMLPropertyState
& rPropState
)
118 aPropStates
.insert(rPropState
);
121 void XMLPropertyStates_Impl::FillPropertyStateVector(
122 std::vector
<XMLPropertyState
>& rVector
)
124 rVector
.insert( rVector
.begin(), aPropStates
.begin(), aPropStates
.end() );
127 class FilterPropertyInfo_Impl
130 std::vector
<sal_uInt32
> maIndexes
;
134 FilterPropertyInfo_Impl( OUString aApiName
,
135 const sal_uInt32 nIndex
);
137 const OUString
& GetApiName() const { return msApiName
; }
138 std::vector
<sal_uInt32
>& GetIndexes() { return maIndexes
; }
141 bool operator< ( const FilterPropertyInfo_Impl
& rArg
) const
143 return (GetApiName() < rArg
.GetApiName());
147 FilterPropertyInfo_Impl::FilterPropertyInfo_Impl(
149 const sal_uInt32 nIndex
) :
150 msApiName(std::move( aApiName
))
152 maIndexes
.push_back(nIndex
);
155 typedef std::list
<FilterPropertyInfo_Impl
> FilterPropertyInfoList_Impl
;
157 class FilterPropertiesInfo_Impl
159 FilterPropertyInfoList_Impl aPropInfos
;
161 std::optional
<Sequence
<OUString
>> mxApiNames
;
164 FilterPropertiesInfo_Impl();
166 void AddProperty(const OUString
& rApiName
, const sal_uInt32 nIndex
);
167 const uno::Sequence
<OUString
>& GetApiNames();
168 void FillPropertyStateArray(
169 std::vector
< XMLPropertyState
>& rPropStates
,
170 const Reference
< XPropertySet
>& xPropSet
,
171 const rtl::Reference
< XMLPropertySetMapper
>& maPropMapper
,
172 const bool bDefault
);
173 sal_uInt32
GetPropertyCount() const { return aPropInfos
.size(); }
176 FilterPropertiesInfo_Impl::FilterPropertiesInfo_Impl()
180 void FilterPropertiesInfo_Impl::AddProperty(
181 const OUString
& rApiName
, const sal_uInt32 nIndex
)
183 aPropInfos
.emplace_back(rApiName
, nIndex
);
185 OSL_ENSURE( !mxApiNames
, "performance warning: API names already retrieved" );
189 const uno::Sequence
<OUString
>& FilterPropertiesInfo_Impl::GetApiNames()
193 // we have to do three things:
194 // 1) sort API names,
195 // 2) merge duplicates,
196 // 3) construct sequence
202 if ( aPropInfos
.size() > 1 )
204 FilterPropertyInfoList_Impl::iterator aOld
= aPropInfos
.begin();
205 FilterPropertyInfoList_Impl::iterator aEnd
= aPropInfos
.end();
206 FilterPropertyInfoList_Impl::iterator aCurrent
= aOld
;
209 while ( aCurrent
!= aEnd
)
211 // equal to next element?
212 if ( aOld
->GetApiName() == aCurrent
->GetApiName() )
214 // if equal: merge index lists
215 std::vector
<sal_uInt32
> aMerged
;
216 std::merge(aOld
->GetIndexes().begin(), aOld
->GetIndexes().end(),
217 aCurrent
->GetIndexes().begin(), aCurrent
->GetIndexes().end(),
218 std::back_inserter(aMerged
));
219 aOld
->GetIndexes() = std::move(aMerged
);
220 aCurrent
->GetIndexes().clear();
221 // erase element, and continue with next
222 aCurrent
= aPropInfos
.erase( aCurrent
);
226 // remember old element and continue with next
233 // construct sequence
234 mxApiNames
.emplace( aPropInfos
.size() );
235 OUString
*pNames
= mxApiNames
->getArray();
237 for (auto const& propInfo
: aPropInfos
)
239 *pNames
= propInfo
.GetApiName();
247 void FilterPropertiesInfo_Impl::FillPropertyStateArray(
248 std::vector
< XMLPropertyState
>& rPropStates
,
249 const Reference
< XPropertySet
>& rPropSet
,
250 const rtl::Reference
< XMLPropertySetMapper
>& rPropMapper
,
251 const bool bDefault
)
253 XMLPropertyStates_Impl aPropStates
;
255 const uno::Sequence
<OUString
>& rApiNames
= GetApiNames();
257 Reference
< XTolerantMultiPropertySet
> xTolPropSet( rPropSet
, UNO_QUERY
);
258 if (xTolPropSet
.is())
262 Sequence
< beans::GetDirectPropertyTolerantResult
> aResults(xTolPropSet
->getDirectPropertyValuesTolerant(rApiNames
));
263 sal_Int32
nResultCount(aResults
.getLength());
264 if (nResultCount
> 0)
266 const beans::GetDirectPropertyTolerantResult
*pResults
= aResults
.getConstArray();
267 FilterPropertyInfoList_Impl::iterator
aPropIter(aPropInfos
.begin());
268 XMLPropertyState
aNewProperty( -1 );
269 while (nResultCount
> 0 && aPropIter
!= aPropInfos
.end())
271 if (pResults
->Name
== aPropIter
->GetApiName())
273 aNewProperty
.mnIndex
= -1;
274 aNewProperty
.maValue
= pResults
->Value
;
276 for (auto const& index
: aPropIter
->GetIndexes())
278 aNewProperty
.mnIndex
= index
;
279 aPropStates
.AddPropertyState( aNewProperty
);
290 const Sequence
< beans::GetPropertyTolerantResult
> aResults(xTolPropSet
->getPropertyValuesTolerant(rApiNames
));
291 OSL_ENSURE( rApiNames
.getLength() == aResults
.getLength(), "wrong implemented XTolerantMultiPropertySet" );
292 FilterPropertyInfoList_Impl::iterator
aPropIter(aPropInfos
.begin());
293 XMLPropertyState
aNewProperty( -1 );
294 OSL_ENSURE( aPropInfos
.size() == static_cast<sal_uInt32
>(aResults
.getLength()), "wrong implemented XTolerantMultiPropertySet??" );
295 for( const auto& rResult
: aResults
)
297 if ((rResult
.Result
== beans::TolerantPropertySetResultType::SUCCESS
) &&
298 ((rResult
.State
== PropertyState_DIRECT_VALUE
) || (rResult
.State
== PropertyState_DEFAULT_VALUE
)))
300 aNewProperty
.mnIndex
= -1;
301 aNewProperty
.maValue
= rResult
.Value
;
303 for (auto const& index
: aPropIter
->GetIndexes())
305 aNewProperty
.mnIndex
= index
;
306 aPropStates
.AddPropertyState( aNewProperty
);
315 Sequence
< PropertyState
> aStates
;
316 const PropertyState
*pStates
= nullptr;
317 Reference
< XPropertyState
> xPropState( rPropSet
, UNO_QUERY
);
318 if( xPropState
.is() )
320 aStates
= xPropState
->getPropertyStates( rApiNames
);
321 pStates
= aStates
.getConstArray();
324 Reference
< XMultiPropertySet
> xMultiPropSet( rPropSet
, UNO_QUERY
);
325 if( xMultiPropSet
.is() && !bDefault
)
327 Sequence
< Any
> aValues
;
330 // step 1: get value count
331 sal_uInt32 nValueCount
= 0;
333 for (size_t i
= 0; i
< aPropInfos
.size(); ++i
, ++pStates
)
335 if( *pStates
== PropertyState_DIRECT_VALUE
)
341 // step 2: collect property names
342 Sequence
< OUString
> aAPINames( nValueCount
);
343 OUString
*pAPINames
= aAPINames
.getArray();
345 ::std::vector
< FilterPropertyInfoList_Impl::iterator
> aPropIters
;
346 aPropIters
.reserve( nValueCount
);
348 FilterPropertyInfoList_Impl::iterator aItr
= aPropInfos
.begin();
349 OSL_ENSURE(aItr
!= aPropInfos
.end(),"Invalid iterator!");
351 pStates
= aStates
.getConstArray();
353 while( i
< nValueCount
)
355 if( *pStates
== PropertyState_DIRECT_VALUE
)
357 *pAPINames
++ = aItr
->GetApiName();
358 aPropIters
.push_back( aItr
);
365 aValues
= xMultiPropSet
->getPropertyValues( aAPINames
);
366 const Any
*pValues
= aValues
.getConstArray();
368 ::std::vector
< FilterPropertyInfoList_Impl::iterator
>::const_iterator
369 pPropIter
= aPropIters
.begin();
371 XMLPropertyState
aNewProperty( -1 );
372 for( i
= 0; i
< nValueCount
; ++i
)
374 aNewProperty
.mnIndex
= -1;
375 aNewProperty
.maValue
= *pValues
;
377 for (auto const& index
: (*pPropIter
)->GetIndexes())
379 aNewProperty
.mnIndex
= index
;
380 aPropStates
.AddPropertyState( aNewProperty
);
390 aValues
= xMultiPropSet
->getPropertyValues( rApiNames
);
391 const Any
*pValues
= aValues
.getConstArray();
393 FilterPropertyInfoList_Impl::iterator aItr
= aPropInfos
.begin();
394 for (size_t i
= 0; i
< aPropInfos
.size(); ++i
)
396 // The value is stored in the PropertySet itself, add to list.
397 XMLPropertyState
aNewProperty( -1 );
398 aNewProperty
.maValue
= *pValues
;
400 for (auto const& index
: aItr
->GetIndexes())
402 aNewProperty
.mnIndex
= index
;
403 aPropStates
.AddPropertyState( aNewProperty
);
411 FilterPropertyInfoList_Impl::iterator aItr
= aPropInfos
.begin();
412 for (size_t i
= 0; i
< aPropInfos
.size(); ++i
)
415 !pStates
|| *pStates
== PropertyState_DIRECT_VALUE
;
416 if( bDirectValue
|| bDefault
)
418 // The value is stored in the PropertySet itself, add to list.
419 bool bGotValue
= false;
420 XMLPropertyState
aNewProperty( -1 );
421 for (auto const& index
: aItr
->GetIndexes())
424 (rPropMapper
->GetEntryFlags(index
) &
425 MID_FLAG_DEFAULT_ITEM_EXPORT
) != 0 )
431 aNewProperty
.maValue
=
432 rPropSet
->getPropertyValue( aItr
->GetApiName() );
435 aNewProperty
.mnIndex
= index
;
436 aPropStates
.AddPropertyState( aNewProperty
);
438 catch( UnknownPropertyException
& )
440 // might be a problem of getImplementationId
441 TOOLS_WARN_EXCEPTION("xmloff.style", "unknown property in getPropertyValue" );
454 aPropStates
.FillPropertyStateVector(rPropStates
);
459 struct SvXMLExportPropertyMapper::Impl
461 typedef std::map
<css::uno::Reference
<css::beans::XPropertySetInfo
>, std::unique_ptr
<FilterPropertiesInfo_Impl
>> CacheType
;
464 rtl::Reference
<SvXMLExportPropertyMapper
> mxNextMapper
;
465 rtl::Reference
<XMLPropertySetMapper
> mxPropMapper
;
467 OUString maStyleName
;
470 // ctor/dtor , class SvXMLExportPropertyMapper
472 SvXMLExportPropertyMapper::SvXMLExportPropertyMapper(
473 const rtl::Reference
< XMLPropertySetMapper
>& rMapper
) :
476 mpImpl
->mxPropMapper
= rMapper
;
479 SvXMLExportPropertyMapper::~SvXMLExportPropertyMapper()
483 void SvXMLExportPropertyMapper::ChainExportMapper(
484 const rtl::Reference
< SvXMLExportPropertyMapper
>& rMapper
)
486 // add map entries from rMapper to current map
487 mpImpl
->mxPropMapper
->AddMapperEntry( rMapper
->getPropertySetMapper() );
488 // rMapper uses the same map as 'this'
489 rMapper
->mpImpl
->mxPropMapper
= mpImpl
->mxPropMapper
;
491 // set rMapper as last mapper in current chain
492 rtl::Reference
< SvXMLExportPropertyMapper
> xNext
= mpImpl
->mxNextMapper
;
495 while (xNext
->mpImpl
->mxNextMapper
.is())
496 xNext
= xNext
->mpImpl
->mxNextMapper
;
497 xNext
->mpImpl
->mxNextMapper
= rMapper
;
500 mpImpl
->mxNextMapper
= rMapper
;
502 // if rMapper was already chained, correct
503 // map pointer of successors
506 while (xNext
->mpImpl
->mxNextMapper
.is())
508 xNext
= xNext
->mpImpl
->mxNextMapper
;
509 xNext
->mpImpl
->mxPropMapper
= mpImpl
->mxPropMapper
;
513 std::vector
<XMLPropertyState
> SvXMLExportPropertyMapper::Filter(
514 SvXMLExport
const& rExport
,
515 const uno::Reference
<beans::XPropertySet
>& rPropSet
, bool bEnableFoFontFamily
) const
517 return Filter_(rExport
, rPropSet
, false, bEnableFoFontFamily
);
520 std::vector
<XMLPropertyState
> SvXMLExportPropertyMapper::FilterDefaults(
521 SvXMLExport
const& rExport
,
522 const uno::Reference
<beans::XPropertySet
>& rPropSet
) const
524 return Filter_(rExport
, rPropSet
, true, false/*bEnableFoFontFamily*/);
527 std::vector
<XMLPropertyState
> SvXMLExportPropertyMapper::Filter_(
528 SvXMLExport
const& rExport
,
529 const Reference
<XPropertySet
>& xPropSet
, bool bDefault
, bool bEnableFoFontFamily
) const
531 std::vector
< XMLPropertyState
> aPropStateArray
;
533 // Retrieve XPropertySetInfo and XPropertyState
534 Reference
< XPropertySetInfo
> xInfo( xPropSet
->getPropertySetInfo() );
536 return aPropStateArray
;
538 sal_Int32 nProps
= mpImpl
->mxPropMapper
->GetEntryCount();
540 FilterPropertiesInfo_Impl
*pFilterInfo
= nullptr;
542 Impl::CacheType::iterator aIter
= mpImpl
->maCache
.find(xInfo
);
543 if (aIter
!= mpImpl
->maCache
.end())
544 pFilterInfo
= (*aIter
).second
.get();
546 bool bDelInfo
= false;
549 assert(GetODFDefaultVersion() != SvtSaveOptions::ODFVER_UNKNOWN
);
550 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentVersion(rExport
.getSaneDefaultVersion());
551 pFilterInfo
= new FilterPropertiesInfo_Impl
;
552 for( sal_Int32 i
=0; i
< nProps
; i
++ )
554 // Are we allowed to ask for the property? (MID_FLAG_NO_PROP..)
555 // Does the PropertySet contain name of mpEntries-array ?
556 const OUString
& rAPIName
= mpImpl
->mxPropMapper
->GetEntryAPIName( i
);
557 const sal_Int32 nFlags
= mpImpl
->mxPropMapper
->GetEntryFlags( i
);
558 if( (0 == (nFlags
& MID_FLAG_NO_PROPERTY_EXPORT
)) &&
559 ( (0 != (nFlags
& MID_FLAG_MUST_EXIST
)) ||
560 xInfo
->hasPropertyByName( rAPIName
) ) )
562 const SvtSaveOptions::ODFSaneDefaultVersion
nEarliestODFVersionForExport(
563 mpImpl
->mxPropMapper
->GetEarliestODFVersionForExport(i
));
564 // note: only standard ODF versions are allowed here,
565 // only exception is the unknown future
566 assert((nEarliestODFVersionForExport
& SvtSaveOptions::ODFSVER_EXTENDED
) == 0
567 || nEarliestODFVersionForExport
== SvtSaveOptions::ODFSVER_FUTURE_EXTENDED
);
568 static_assert(SvtSaveOptions::ODFSVER_LATEST_EXTENDED
< SvtSaveOptions::ODFSVER_FUTURE_EXTENDED
);
569 /// standard ODF namespaces for elements and attributes
570 static sal_uInt16 s_OdfNs
[] = {
571 XML_NAMESPACE_OFFICE
,
580 XML_NAMESPACE_NUMBER
,
581 XML_NAMESPACE_PRESENTATION
,
587 XML_NAMESPACE_SCRIPT
,
588 XML_NAMESPACE_CONFIG
,
590 XML_NAMESPACE_XFORMS
,
592 XML_NAMESPACE_ANIMATION
,
597 static bool s_Assert(false);
600 assert(std::is_sorted(std::begin(s_OdfNs
), std::end(s_OdfNs
)));
603 //static_assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs)));
604 auto const ns(mpImpl
->mxPropMapper
->GetEntryNameSpace(i
));
605 auto const iter(std::lower_bound(std::begin(s_OdfNs
), std::end(s_OdfNs
),
607 bool const isExtension(iter
== std::end(s_OdfNs
) || *iter
!= ns
608 // FIXME: very special hack to suppress style:hyperlink
609 || (ns
== XML_NAMESPACE_STYLE
610 && mpImpl
->mxPropMapper
->GetEntryXMLName(i
) == GetXMLToken(XML_HYPERLINK
)));
612 ? ((nCurrentVersion
& SvtSaveOptions::ODFSVER_EXTENDED
)
613 // if it's in standard ODF, don't export extension
614 && (nCurrentVersion
< nEarliestODFVersionForExport
))
615 : (nEarliestODFVersionForExport
<= nCurrentVersion
))
617 pFilterInfo
->AddProperty(rAPIName
, i
);
622 // Check whether the property set info is destroyed if it is assigned to
623 // a weak reference only; If it is destroyed, then every instance of
624 // getPropertySetInfo returns a new object; such property set infos must
626 WeakReference
< XPropertySetInfo
> xWeakInfo( xInfo
);
631 mpImpl
->maCache
.emplace(xInfo
, std::unique_ptr
<FilterPropertiesInfo_Impl
>(pFilterInfo
));
637 if( pFilterInfo
->GetPropertyCount() )
641 pFilterInfo
->FillPropertyStateArray(
642 aPropStateArray
, xPropSet
, mpImpl
->mxPropMapper
, bDefault
);
644 catch( UnknownPropertyException
& )
646 // might be a problem of getImplementationId
647 TOOLS_WARN_EXCEPTION("xmloff.style", "unknown property in getPropertyStates" );
651 // Call context-filter
652 if( !aPropStateArray
.empty() )
653 ContextFilter(bEnableFoFontFamily
, aPropStateArray
, xPropSet
);
655 // Have to do if we change from a vector to a list or something like that
660 return aPropStateArray
;
663 void SvXMLExportPropertyMapper::ContextFilter(
664 bool bEnableFoFontFamily
,
665 std::vector
< XMLPropertyState
>& rProperties
,
666 const Reference
< XPropertySet
>& rPropSet
) const
668 // Derived class could implement this.
669 if (mpImpl
->mxNextMapper
.is())
670 mpImpl
->mxNextMapper
->ContextFilter(bEnableFoFontFamily
, rProperties
, rPropSet
);
673 // Compares two Sequences of XMLPropertyState:
674 // 1.Number of elements equal ?
675 // 2.Index of each element equal ? (So I know whether the propertynames are the same)
676 // 3.Value of each element equal ?
677 bool SvXMLExportPropertyMapper::Equals(
678 const std::vector
< XMLPropertyState
>& aProperties1
,
679 const std::vector
< XMLPropertyState
>& aProperties2
) const
681 if (aProperties1
.size() < aProperties2
.size())
683 if (aProperties1
.size() > aProperties2
.size())
686 sal_uInt32 nCount
= aProperties1
.size();
688 for (sal_uInt32 nIndex
= 0; nIndex
< nCount
; ++nIndex
)
690 const XMLPropertyState
& rProp1
= aProperties1
[ nIndex
];
691 const XMLPropertyState
& rProp2
= aProperties2
[ nIndex
];
693 // Compare index. If equal, compare value
694 if( rProp1
.mnIndex
< rProp2
.mnIndex
)
696 if( rProp1
.mnIndex
> rProp2
.mnIndex
)
699 if( rProp1
.mnIndex
!= -1 )
701 // Now compare values
702 if ( (mpImpl
->mxPropMapper
->GetEntryType( rProp1
.mnIndex
) &
703 XML_TYPE_BUILDIN_CMP
) != 0 )
705 // simple type ( binary compare )
706 if ( rProp1
.maValue
!= rProp2
.maValue
)
711 // complex type ( ask for compare-function )
712 if (!mpImpl
->mxPropMapper
->GetPropertyHandler(
713 rProp1
.mnIndex
)->equals( rProp1
.maValue
,
723 // Compares two Sequences of XMLPropertyState:
724 // 1.Number of elements equal ?
725 // 2.Index of each element equal ? (So I know whether the propertynames are the same)
726 // 3.Value of each element equal ?
727 bool SvXMLExportPropertyMapper::LessPartial(
728 const std::vector
< XMLPropertyState
>& aProperties1
,
729 const std::vector
< XMLPropertyState
>& aProperties2
) const
731 if (aProperties1
.size() < aProperties2
.size())
733 if (aProperties1
.size() > aProperties2
.size())
736 sal_uInt32 nCount
= aProperties1
.size();
738 for (sal_uInt32 nIndex
= 0; nIndex
< nCount
; ++nIndex
)
740 const XMLPropertyState
& rProp1
= aProperties1
[ nIndex
];
741 const XMLPropertyState
& rProp2
= aProperties2
[ nIndex
];
743 // Compare index. If equal, compare value
744 if( rProp1
.mnIndex
< rProp2
.mnIndex
)
746 if( rProp1
.mnIndex
> rProp2
.mnIndex
)
749 if( rProp1
.mnIndex
!= -1 )
751 // Now compare values
752 if ( (mpImpl
->mxPropMapper
->GetEntryType( rProp1
.mnIndex
) &
753 XML_TYPE_BUILDIN_CMP
) != 0 )
755 // simple type ( binary compare )
756 if ( comphelper::anyLess(rProp1
.maValue
, rProp2
.maValue
) )
758 if ( comphelper::anyLess(rProp2
.maValue
, rProp1
.maValue
) )
767 /** fills the given attribute list with the items in the given set
768 void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList,
769 const ::std::vector< XMLPropertyState >& rProperties,
770 const SvXMLUnitConverter& rUnitConverter,
771 const SvXMLNamespaceMap& rNamespaceMap,
772 sal_uInt16 nFlags ) const
774 _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap,
778 void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList,
779 const ::std::vector< XMLPropertyState >& rProperties,
780 const SvXMLUnitConverter& rUnitConverter,
781 const SvXMLNamespaceMap& rNamespaceMap,
782 sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx,
783 sal_uInt16 nFlags ) const
785 _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap,
786 nFlags, 0, nPropMapStartIdx, nPropMapEndIdx );
790 void SvXMLExportPropertyMapper::exportXML(
791 SvXMLExport
& rExport
,
792 const ::std::vector
< XMLPropertyState
>& rProperties
,
793 SvXmlExportFlags nFlags
,
794 bool bUseExtensionNamespaceForGraphicProperties
) const
796 exportXML(rExport
, rProperties
, -1, -1, nFlags
, bUseExtensionNamespaceForGraphicProperties
);
800 void SvXMLExportPropertyMapper::exportXML(
801 SvXMLExport
& rExport
,
802 const ::std::vector
< XMLPropertyState
>& rProperties
,
803 sal_Int32 nPropMapStartIdx
, sal_Int32 nPropMapEndIdx
,
804 SvXmlExportFlags nFlags
, bool bUseExtensionNamespaceForGraphicProperties
) const
806 sal_uInt16 nPropTypeFlags
= 0;
807 for( sal_uInt16 i
=0; i
<MAX_PROP_TYPES
; ++i
)
809 sal_uInt16 nPropType
= aPropTokens
[i
].nType
;
810 if( 0==i
|| (nPropTypeFlags
& (1 << nPropType
)) != 0 )
812 sal_uInt16 nNamespace
= XML_NAMESPACE_STYLE
;
813 if (bUseExtensionNamespaceForGraphicProperties
&&
814 aPropTokens
[i
].eToken
== xmloff::token::XML_GRAPHIC_PROPERTIES
)
816 nNamespace
= XML_NAMESPACE_LO_EXT
;
817 if ((rExport
.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED
) == 0)
819 continue; // don't write for ODF <= 1.2
823 std::vector
<sal_uInt16
> aIndexArray
;
825 _exportXML( nPropType
, nPropTypeFlags
,
826 rExport
.GetAttrList(), rProperties
,
827 rExport
.GetMM100UnitConverter(),
828 rExport
.GetNamespaceMap(),
830 nPropMapStartIdx
, nPropMapEndIdx
);
832 if( rExport
.GetAttrList().getLength() > 0 ||
833 !aIndexArray
.empty() )
835 SvXMLElementExport
aElem( rExport
, nNamespace
,
836 aPropTokens
[i
].eToken
,
837 bool(nFlags
& SvXmlExportFlags::IGN_WS
),
840 exportElementItems( rExport
, rProperties
, nFlags
, aIndexArray
);
846 /** this method is called for every item that has the
847 MID_FLAG_SPECIAL_ITEM_EXPORT flag set */
848 void SvXMLExportPropertyMapper::handleSpecialItem(
849 comphelper::AttributeList
& rAttrList
,
850 const XMLPropertyState
& rProperty
,
851 const SvXMLUnitConverter
& rUnitConverter
,
852 const SvXMLNamespaceMap
& rNamespaceMap
,
853 const ::std::vector
< XMLPropertyState
> *pProperties
,
854 sal_uInt32 nIdx
) const
856 OSL_ENSURE(mpImpl
->mxNextMapper
.is(), "special item not handled in xml export");
857 if (mpImpl
->mxNextMapper
.is())
858 mpImpl
->mxNextMapper
->handleSpecialItem(
859 rAttrList
, rProperty
, rUnitConverter
, rNamespaceMap
, pProperties
, nIdx
);
862 /** this method is called for every item that has the
863 MID_FLAG_ELEMENT_EXPORT flag set */
864 void SvXMLExportPropertyMapper::handleElementItem(
865 SvXMLExport
& rExport
,
866 const XMLPropertyState
& rProperty
,
867 SvXmlExportFlags nFlags
,
868 const ::std::vector
< XMLPropertyState
> *pProperties
,
869 sal_uInt32 nIdx
) const
871 OSL_ENSURE(mpImpl
->mxNextMapper
.is(), "element item not handled in xml export");
872 if (mpImpl
->mxNextMapper
.is())
873 mpImpl
->mxNextMapper
->handleElementItem(rExport
, rProperty
, nFlags
, pProperties
, nIdx
);
878 /** fills the given attribute list with the items in the given set */
879 void SvXMLExportPropertyMapper::_exportXML(
880 sal_uInt16 nPropType
, sal_uInt16
& rPropTypeFlags
,
881 comphelper::AttributeList
& rAttrList
,
882 const ::std::vector
< XMLPropertyState
>& rProperties
,
883 const SvXMLUnitConverter
& rUnitConverter
,
884 const SvXMLNamespaceMap
& rNamespaceMap
,
885 std::vector
<sal_uInt16
>* pIndexArray
,
886 sal_Int32 nPropMapStartIdx
, sal_Int32 nPropMapEndIdx
) const
888 const sal_uInt32 nCount
= rProperties
.size();
889 sal_uInt32 nIndex
= 0;
891 if( -1 == nPropMapStartIdx
)
892 nPropMapStartIdx
= 0;
893 if( -1 == nPropMapEndIdx
)
894 nPropMapEndIdx
= mpImpl
->mxPropMapper
->GetEntryCount();
896 while( nIndex
< nCount
)
898 sal_Int32 nPropMapIdx
= rProperties
[nIndex
].mnIndex
;
899 if( nPropMapIdx
>= nPropMapStartIdx
&&
900 nPropMapIdx
< nPropMapEndIdx
)// valid entry?
902 sal_uInt32 nEFlags
= mpImpl
->mxPropMapper
->GetEntryFlags(nPropMapIdx
);
903 sal_uInt16 nEPType
= GET_PROP_TYPE(nEFlags
);
904 OSL_ENSURE(nEPType
>= (XML_TYPE_PROP_START
>> XML_TYPE_PROP_SHIFT
),
905 "no prop type specified");
906 rPropTypeFlags
|= (1 << nEPType
);
907 if( nEPType
== nPropType
)
909 // we have a valid map entry here, so lets use it...
910 if( ( nEFlags
& MID_FLAG_ELEMENT_ITEM_EXPORT
) != 0 )
912 // element items do not add any properties,
913 // we export it later
916 pIndexArray
->push_back( static_cast<sal_uInt16
>(nIndex
) );
921 _exportXML( rAttrList
, rProperties
[nIndex
], rUnitConverter
,
922 rNamespaceMap
, &rProperties
, nIndex
);
933 // -1 = Attribute needs extended namespace, but current ODF version is strict.
934 // 1 = Attribute needs extended namespace and current ODF version allows it.
935 // 0 = Attribute does not need extended namespace
936 sal_Int8
CheckExtendedNamespace(std::u16string_view sXMLAttributeName
, std::u16string_view sValue
,
937 const SvtSaveOptions::ODFSaneDefaultVersion nODFVersion
)
939 if (IsXMLToken(sXMLAttributeName
, XML_WRITING_MODE
)
940 && (IsXMLToken(sValue
, XML_BT_LR
) || IsXMLToken(sValue
, XML_TB_RL90
)))
941 return nODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
? 1 : -1;
942 else if (IsXMLToken(sXMLAttributeName
, XML_VERTICAL_REL
)
943 && (IsXMLToken(sValue
, XML_PAGE_CONTENT_BOTTOM
)
944 || IsXMLToken(sValue
, XML_PAGE_CONTENT_TOP
)))
945 return nODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
? 1 : -1;
950 void SvXMLExportPropertyMapper::_exportXML(
951 comphelper::AttributeList
& rAttrList
,
952 const XMLPropertyState
& rProperty
,
953 const SvXMLUnitConverter
& rUnitConverter
,
954 const SvXMLNamespaceMap
& rNamespaceMap
,
955 const ::std::vector
< XMLPropertyState
> *pProperties
,
956 sal_uInt32 nIdx
) const
958 if ((mpImpl
->mxPropMapper
->GetEntryFlags(rProperty
.mnIndex
) & MID_FLAG_SPECIAL_ITEM_EXPORT
) != 0)
960 uno::Reference
< container::XNameContainer
> xAttrContainer
;
961 if( (rProperty
.maValue
>>= xAttrContainer
) && xAttrContainer
.is() )
963 std::unique_ptr
<SvXMLNamespaceMap
> pNewNamespaceMap
;
964 const SvXMLNamespaceMap
*pNamespaceMap
= &rNamespaceMap
;
966 const uno::Sequence
< OUString
> aAttribNames( xAttrContainer
->getElementNames() );
968 xml::AttributeData aData
;
969 for( const auto& rAttribName
: aAttribNames
)
971 xAttrContainer
->getByName( rAttribName
) >>= aData
;
972 OUString
sAttribName( rAttribName
);
974 // extract namespace prefix from attribute name if it exists
976 const sal_Int32 nColonPos
=
977 rAttribName
.indexOf( ':' );
978 if( nColonPos
!= -1 )
979 sPrefix
= rAttribName
.copy( 0, nColonPos
);
981 if( !sPrefix
.isEmpty() )
983 OUString
sNamespace( aData
.Namespace
);
985 // if the prefix isn't defined yet or has another meaning,
986 // we have to redefine it now.
987 sal_uInt16 nKey
= pNamespaceMap
->GetKeyByPrefix( sPrefix
);
988 if( USHRT_MAX
== nKey
|| pNamespaceMap
->GetNameByKey( nKey
) != sNamespace
)
990 bool bAddNamespace
= false;
991 if( USHRT_MAX
== nKey
)
993 // The prefix is unused, so it is sufficient
994 // to add it to the namespace map.
995 bAddNamespace
= true;
999 // check if there is a prefix registered for the
1001 nKey
= pNamespaceMap
->GetKeyByName( sNamespace
);
1002 if( XML_NAMESPACE_UNKNOWN
== nKey
)
1004 // There is no prefix for the namespace, so
1005 // we have to generate one and have to add it.
1007 OUString
sOrigPrefix( sPrefix
);
1010 sPrefix
= sOrigPrefix
+ OUString::number( ++n
);
1011 nKey
= pNamespaceMap
->GetKeyByPrefix( sPrefix
);
1013 while( nKey
!= USHRT_MAX
);
1015 bAddNamespace
= true;
1019 // If there is a prefix for the namespace,
1021 sPrefix
= pNamespaceMap
->GetPrefixByKey( nKey
);
1023 // In any case, the attribute name has to be adapted.
1024 sAttribName
= sPrefix
+ ":" + rAttribName
.subView(nColonPos
+1);
1029 if( !pNewNamespaceMap
)
1031 pNewNamespaceMap
.reset(new SvXMLNamespaceMap( rNamespaceMap
));
1032 pNamespaceMap
= pNewNamespaceMap
.get();
1034 pNewNamespaceMap
->Add( sPrefix
, sNamespace
);
1035 OUString sAttr
= GetXMLToken(XML_XMLNS
) + ":" + sPrefix
;
1036 rAttrList
.AddAttribute( sAttr
, sNamespace
);
1040 OUString
sOldValue( rAttrList
.getValueByName( sAttribName
) );
1041 OSL_ENSURE( sOldValue
.isEmpty(), "alien attribute exists already" );
1042 OSL_ENSURE(aData
.Type
== GetXMLToken(XML_CDATA
), "different type to our default type which should be written out");
1043 if( sOldValue
.isEmpty() )
1044 rAttrList
.AddAttribute( sAttribName
, aData
.Value
);
1049 handleSpecialItem( rAttrList
, rProperty
, rUnitConverter
,
1050 rNamespaceMap
, pProperties
, nIdx
);
1053 else if ((mpImpl
->mxPropMapper
->GetEntryFlags(rProperty
.mnIndex
) & MID_FLAG_ELEMENT_ITEM_EXPORT
) == 0)
1056 OUString sName
= rNamespaceMap
.GetQNameByKey(
1057 mpImpl
->mxPropMapper
->GetEntryNameSpace(rProperty
.mnIndex
),
1058 mpImpl
->mxPropMapper
->GetEntryXMLName(rProperty
.mnIndex
));
1060 bool bRemove
= false;
1061 if ((mpImpl
->mxPropMapper
->GetEntryFlags( rProperty
.mnIndex
) & MID_FLAG_MERGE_ATTRIBUTE
) != 0)
1063 aValue
= rAttrList
.getValueByName( sName
);
1067 if (mpImpl
->mxPropMapper
->exportXML(aValue
, rProperty
, rUnitConverter
))
1070 rAttrList
.RemoveAttribute( sName
);
1072 // We don't seem to have a generic mechanism to write an attribute in the extension
1073 // namespace in case of certain attribute values only, so do this manually.
1074 sal_Int8 nExtendedStatus
1075 = CheckExtendedNamespace(mpImpl
->mxPropMapper
->GetEntryXMLName(rProperty
.mnIndex
),
1076 aValue
, rUnitConverter
.getSaneDefaultVersion());
1077 if (nExtendedStatus
== -1)
1079 if (nExtendedStatus
== 1)
1080 sName
= rNamespaceMap
.GetQNameByKey(
1081 XML_NAMESPACE_LO_EXT
, mpImpl
->mxPropMapper
->GetEntryXMLName(rProperty
.mnIndex
));
1082 rAttrList
.AddAttribute( sName
, aValue
);
1087 void SvXMLExportPropertyMapper::exportElementItems(
1088 SvXMLExport
& rExport
,
1089 const ::std::vector
< XMLPropertyState
>& rProperties
,
1090 SvXmlExportFlags nFlags
,
1091 const std::vector
<sal_uInt16
>& rIndexArray
) const
1093 bool bItemsExported
= false;
1094 for (const sal_uInt16 nElement
: rIndexArray
)
1096 OSL_ENSURE( 0 != (mpImpl
->mxPropMapper
->GetEntryFlags(
1097 rProperties
[nElement
].mnIndex
) & MID_FLAG_ELEMENT_ITEM_EXPORT
),
1098 "wrong mid flag!" );
1100 rExport
.IgnorableWhitespace();
1101 handleElementItem( rExport
, rProperties
[nElement
],
1102 nFlags
, &rProperties
, nElement
);
1103 bItemsExported
= true;
1106 if( bItemsExported
)
1107 rExport
.IgnorableWhitespace();
1110 const rtl::Reference
<XMLPropertySetMapper
>& SvXMLExportPropertyMapper::getPropertySetMapper() const
1112 return mpImpl
->mxPropMapper
;
1115 void SvXMLExportPropertyMapper::SetStyleName( const OUString
& rStyleName
)
1117 mpImpl
->maStyleName
= rStyleName
;
1120 const OUString
& SvXMLExportPropertyMapper::GetStyleName() const
1122 return mpImpl
->maStyleName
;
1125 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */