1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <memory>
21 #include <algorithm>
22 
23 #include <rtl/ustrbuf.hxx>
24 #include <sal/log.hxx>
25 #include <tools/solar.h>
26 #include <xmloff/PageMasterStyleMap.hxx>
27 #include <xmloff/families.hxx>
28 #include <xmloff/xmlaustp.hxx>
29 #include <xmloff/xmlexp.hxx>
30 #include <xmloff/xmlexppr.hxx>
31 #include <xmloff/xmlnmspe.hxx>
32 #include <xmloff/xmlprmap.hxx>
33 #include <xmloff/xmltoken.hxx>
34 
35 #include "impastpl.hxx"
36 
37 using namespace ::std;
38 
39 using namespace ::com::sun::star;
40 using namespace ::xmloff::token;
41 
42 // Class XMLAutoStyleFamily
43 // ctor/dtor class XMLAutoStyleFamily
44 
XMLAutoStyleFamily(sal_Int32 nFamily,const OUString & rStrName,const rtl::Reference<SvXMLExportPropertyMapper> & rMapper,const OUString & rStrPrefix,bool bAsFamily)45 XMLAutoStyleFamily::XMLAutoStyleFamily(
46         sal_Int32 nFamily,
47         const OUString& rStrName,
48         const rtl::Reference < SvXMLExportPropertyMapper > &rMapper,
49         const OUString& rStrPrefix,
50         bool bAsFamily ) :
51     mnFamily( nFamily ), maStrFamilyName( rStrName), mxMapper( rMapper ),
52     mnCount( 0 ), mnName( 0 ), maStrPrefix( rStrPrefix ), mbAsFamily( bAsFamily )
53 {}
54 
XMLAutoStyleFamily(sal_Int32 nFamily)55 XMLAutoStyleFamily::XMLAutoStyleFamily( sal_Int32 nFamily ) :
56     mnFamily(nFamily), mnCount(0), mnName(0), mbAsFamily(false) {}
57 
ClearEntries()58 void XMLAutoStyleFamily::ClearEntries()
59 {
60     m_ParentSet.clear();
61 }
62 
63 static OUString
64 data2string(void *data,
65             const typelib_TypeDescriptionReference *type);
66 
67 static OUString
struct2string(void * data,const typelib_TypeDescription * type)68 struct2string(void *data,
69               const typelib_TypeDescription *type)
70 {
71     assert(type->eTypeClass == typelib_TypeClass_STRUCT);
72 
73     OUStringBuffer result;
74 
75     result.append("{");
76 
77     const typelib_CompoundTypeDescription *compoundType =
78         &reinterpret_cast<const typelib_StructTypeDescription*>(type)->aBase;
79 
80     for (int i = 0; i < compoundType->nMembers; i++)
81     {
82         if (i > 0)
83             result.append(":");
84         result.append(compoundType->ppMemberNames[i]);
85         result.append("=");
86         result.append(data2string(static_cast<char *>(data)+compoundType->pMemberOffsets[i],
87                                   compoundType->ppTypeRefs[i]));
88     }
89 
90     result.append("}");
91 
92     return result.makeStringAndClear();
93 }
94 
95 static OUString
data2string(void * data,const typelib_TypeDescriptionReference * type)96 data2string(void *data,
97             const typelib_TypeDescriptionReference *type)
98 {
99     switch (type->eTypeClass)
100     {
101     case typelib_TypeClass_VOID:
102         return "";
103     case typelib_TypeClass_BOOLEAN:
104         return *static_cast<const sal_Bool*>(data) ? OUString("true") : OUString("false");
105     case typelib_TypeClass_BYTE:
106         return OUString::number((*static_cast<const sal_Int8*>(data)));
107     case typelib_TypeClass_SHORT:
108         return OUString::number((*static_cast<const sal_Int16*>(data)));
109     case typelib_TypeClass_LONG:
110         return OUString::number((*static_cast<const sal_Int32*>(data)));
111     case typelib_TypeClass_HYPER:
112         return OUString::number((*static_cast<const sal_Int64*>(data)));
113     case typelib_TypeClass_UNSIGNED_SHORT:
114         return OUString::number((*static_cast<const sal_uInt16*>(data)));
115     case typelib_TypeClass_UNSIGNED_LONG:
116         return OUString::number((*static_cast<const sal_uInt32*>(data)), 16);
117     case typelib_TypeClass_UNSIGNED_HYPER:
118         return OUString::number((*static_cast<const sal_uInt64*>(data)), 16);
119     case typelib_TypeClass_FLOAT:
120         return OUString::number(*static_cast<const float*>(data));
121     case typelib_TypeClass_DOUBLE:
122         return OUString::number(*static_cast<const double*>(data));
123     case typelib_TypeClass_CHAR:
124         return ("U+" + OUString::number((*static_cast<const sal_uInt16*>(data))));
125     case typelib_TypeClass_STRING:
126         return *static_cast<OUString*>(data);
127     case typelib_TypeClass_TYPE:
128     case typelib_TypeClass_SEQUENCE:
129     case typelib_TypeClass_EXCEPTION:
130     case typelib_TypeClass_INTERFACE:
131         return "wtf";
132     case typelib_TypeClass_STRUCT:
133         return struct2string(data, type->pType);
134     case typelib_TypeClass_ENUM:
135         return OUString::number((*static_cast<const sal_Int32*>(data)));
136     default:
137         assert(false); // this cannot happen I hope
138         break;
139     }
140     return "";
141 }
142 
any2string(const uno::Any & any)143 static OUString any2string(const uno::Any& any)
144 {
145     return data2string(const_cast<void*>(any.getValue()), any.pType);
146 }
147 
148 // Class SvXMLAutoStylePoolProperties_Impl
149 // ctor class SvXMLAutoStylePoolProperties_Impl
150 
XMLAutoStylePoolProperties(XMLAutoStyleFamily & rFamilyData,const vector<XMLPropertyState> & rProperties,OUString const & rParentName)151 XMLAutoStylePoolProperties::XMLAutoStylePoolProperties( XMLAutoStyleFamily& rFamilyData, const vector< XMLPropertyState >& rProperties, OUString const & rParentName )
152 : maProperties( rProperties ),
153   mnPos       ( rFamilyData.mnCount )
154 {
155     static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr);
156 
157     if (bHack)
158     {
159         OUStringBuffer aStemBuffer(32);
160         aStemBuffer.append( rFamilyData.maStrPrefix );
161 
162         if (!rParentName.isEmpty())
163             {
164                 aStemBuffer.append("-");
165                 aStemBuffer.append(rParentName);
166             }
167 
168         // Create a name based on the properties used
169         for(XMLPropertyState const & rState : maProperties)
170             {
171                 if (rState.mnIndex == -1)
172                     continue;
173                 OUString sXMLName(rFamilyData.mxMapper->getPropertySetMapper()->GetEntryXMLName(rState.mnIndex));
174                 if (sXMLName.isEmpty())
175                     continue;
176                 aStemBuffer.append("-");
177                 aStemBuffer.append(OUString::number(rFamilyData.mxMapper->getPropertySetMapper()->GetEntryNameSpace(rState.mnIndex)));
178                 aStemBuffer.append(":");
179                 aStemBuffer.append(sXMLName);
180                 aStemBuffer.append("=");
181                 aStemBuffer.append(any2string(rState.maValue));
182             }
183 
184 #if 0
185         // Finally append an incremental counter in an attempt to make identical
186         // styles always come out in the same order. Will see if this works.
187         aStemBuffer.append("-z");
188         static sal_Int32 nCounter = 0;
189         aStemBuffer.append(OUString::number(nCounter++));
190 #endif
191 
192         // create a name that hasn't been used before. The created name has not
193         // to be added to the array, because it will never tried again
194         OUStringBuffer aTry( aStemBuffer );
195 
196         msName = aTry.makeStringAndClear();
197         bool bWarned = false;
198         while (rFamilyData.maNameSet.find(msName) !=
199                rFamilyData.maNameSet.end())
200         {
201             if (!bWarned)
202                 SAL_WARN("xmloff", "Overlapping style name for " << msName);
203             bWarned = true;
204             rFamilyData.mnName++;
205             aTry.append( aStemBuffer );
206             aTry.append( "-" );
207             aTry.append( OUString::number( rFamilyData.mnName ) );
208             msName = aTry.makeStringAndClear();
209         }
210         rFamilyData.maNameSet.insert(msName);
211     }
212     else
213     {
214         // create a name that hasn't been used before. The created name has not
215         // to be added to the array, because it will never tried again
216         OUStringBuffer sBuffer( 7 );
217         do
218         {
219             rFamilyData.mnName++;
220             sBuffer.append( rFamilyData.maStrPrefix );
221             sBuffer.append( OUString::number( rFamilyData.mnName ) );
222             msName = sBuffer.makeStringAndClear();
223         }
224         while (rFamilyData.maNameSet.find(msName) != rFamilyData.maNameSet.end() || rFamilyData.maReservedNameSet.find(msName) != rFamilyData.maReservedNameSet.end());
225     }
226 
227 #if OSL_DEBUG_LEVEL > 0
228     std::set<sal_Int32> DebugProperties;
229     for (XMLPropertyState const & rPropState : maProperties)
230     {
231         sal_Int32 const property(rPropState.mnIndex);
232         // serious bug: will cause duplicate attributes to be exported
233         assert(DebugProperties.find(property) == DebugProperties.end());
234         if (-1 != property)
235         {
236             DebugProperties.insert(property);
237         }
238     }
239 #endif
240 }
241 
operator <(const XMLAutoStyleFamily & r1,const XMLAutoStyleFamily & r2)242 bool operator<( const XMLAutoStyleFamily& r1, const XMLAutoStyleFamily& r2)
243 {
244     return r1.mnFamily < r2.mnFamily;
245 }
246 
247 
~XMLAutoStylePoolParent()248 XMLAutoStylePoolParent::~XMLAutoStylePoolParent()
249 {
250 }
251 
252 struct ComparePartial
253 {
254     const XMLAutoStyleFamily& rFamilyData;
255 
operator ()ComparePartial256     bool operator()(const vector< XMLPropertyState >& lhs,
257                     const std::unique_ptr<XMLAutoStylePoolProperties>& rhs) const
258     {
259         return rFamilyData.mxMapper->LessPartial(lhs, rhs->GetProperties());
260     }
operator ()ComparePartial261     bool operator()(const std::unique_ptr<XMLAutoStylePoolProperties>& lhs,
262                     const vector< XMLPropertyState >& rhs ) const
263     {
264         return rFamilyData.mxMapper->LessPartial(lhs->GetProperties(), rhs);
265     }
266 };
267 
268 // Adds an array of XMLPropertyState ( vector< XMLPropertyState > ) to list
269 // if not added, yet.
270 
Add(XMLAutoStyleFamily & rFamilyData,const vector<XMLPropertyState> & rProperties,OUString & rName,bool bDontSeek)271 bool XMLAutoStylePoolParent::Add( XMLAutoStyleFamily& rFamilyData, const vector< XMLPropertyState >& rProperties, OUString& rName, bool bDontSeek )
272 {
273     XMLAutoStylePoolProperties *pProperties = nullptr;
274     auto [itBegin, itEnd] = std::equal_range(m_PropertiesList.begin(), m_PropertiesList.end(), rProperties, ComparePartial{rFamilyData});
275     if (!bDontSeek)
276         for (auto it = itBegin; it != itEnd; ++it)
277             if (rFamilyData.mxMapper->Equals((*it)->GetProperties(), rProperties))
278                 pProperties = it->get();
279 
280     bool bAdded = false;
281     if( bDontSeek || !pProperties )
282     {
283         pProperties = new XMLAutoStylePoolProperties( rFamilyData, rProperties, msParent );
284         m_PropertiesList.insert(itBegin, std::unique_ptr<XMLAutoStylePoolProperties>(pProperties));
285         bAdded = true;
286     }
287 
288     rName = pProperties->GetName();
289 
290     return bAdded;
291 }
292 
293 
294 // Adds an array of XMLPropertyState ( vector< XMLPropertyState > ) with a given name.
295 // If the name exists already, nothing is done. If a style with a different name and
296 // the same properties exists, a new one is added (like with bDontSeek).
297 
298 
AddNamed(XMLAutoStyleFamily & rFamilyData,const vector<XMLPropertyState> & rProperties,const OUString & rName)299 bool XMLAutoStylePoolParent::AddNamed( XMLAutoStyleFamily& rFamilyData, const vector< XMLPropertyState >& rProperties, const OUString& rName )
300 {
301     if (rFamilyData.maNameSet.find(rName) != rFamilyData.maNameSet.end())
302         return false;
303 
304     auto it = std::lower_bound(m_PropertiesList.begin(), m_PropertiesList.end(), rProperties, ComparePartial{rFamilyData});
305 
306     std::unique_ptr<XMLAutoStylePoolProperties> pProperties(
307         new XMLAutoStylePoolProperties(rFamilyData, rProperties, msParent));
308     // ignore the generated name
309     pProperties->SetName( rName );
310     m_PropertiesList.insert(it, std::move(pProperties));
311     return true;
312 }
313 
314 
315 // Search for an array of XMLPropertyState ( vector< XMLPropertyState > ) in list
316 
317 
Find(const XMLAutoStyleFamily & rFamilyData,const vector<XMLPropertyState> & rProperties) const318 OUString XMLAutoStylePoolParent::Find( const XMLAutoStyleFamily& rFamilyData, const vector< XMLPropertyState >& rProperties ) const
319 {
320     OUString sName;
321     auto [itBegin,itEnd] = std::equal_range(m_PropertiesList.begin(), m_PropertiesList.end(), rProperties, ComparePartial{rFamilyData});
322     for (auto it = itBegin; it != itEnd; ++it)
323         if (rFamilyData.mxMapper->Equals((*it)->GetProperties(), rProperties))
324             sName = (*it)->GetName();
325 
326     return sName;
327 }
328 
operator <(const XMLAutoStylePoolParent & rOther) const329 bool XMLAutoStylePoolParent::operator< (const XMLAutoStylePoolParent& rOther) const
330 {
331     return msParent < rOther.msParent;
332 }
333 
334 // Class SvXMLAutoStylePool_Impl
335 // ctor/dtor class SvXMLAutoStylePool_Impl
336 
SvXMLAutoStylePoolP_Impl(SvXMLExport & rExp)337 SvXMLAutoStylePoolP_Impl::SvXMLAutoStylePoolP_Impl( SvXMLExport& rExp)
338     :   rExport( rExp )
339 {
340 }
341 
~SvXMLAutoStylePoolP_Impl()342 SvXMLAutoStylePoolP_Impl::~SvXMLAutoStylePoolP_Impl()
343 {
344 }
345 
346 // Adds stylefamily-information to sorted list
347 
AddFamily(sal_Int32 nFamily,const OUString & rStrName,const rtl::Reference<SvXMLExportPropertyMapper> & rMapper,const OUString & rStrPrefix,bool bAsFamily)348 void SvXMLAutoStylePoolP_Impl::AddFamily(
349         sal_Int32 nFamily,
350         const OUString& rStrName,
351         const rtl::Reference < SvXMLExportPropertyMapper > & rMapper,
352            const OUString& rStrPrefix,
353         bool bAsFamily )
354 {
355     // store family in a list if not already stored
356     SvXMLExportFlags nExportFlags = GetExport().getExportFlags();
357     bool bStylesOnly = (nExportFlags & SvXMLExportFlags::STYLES) && !(nExportFlags & SvXMLExportFlags::CONTENT);
358 
359     OUString aPrefix( rStrPrefix );
360     if( bStylesOnly )
361     {
362         aPrefix = "M" + rStrPrefix;
363     }
364 
365 #if OSL_DEBUG_LEVEL > 0
366     std::unique_ptr<XMLAutoStyleFamily> pTemp(new XMLAutoStyleFamily(nFamily));
367     auto const iter = m_FamilySet.find(pTemp);
368     if (iter != m_FamilySet.end())
369     {
370         // FIXME: do we really intend to replace the previous nFamily
371         // entry in this case ?
372         SAL_WARN_IF( (*iter)->mxMapper != rMapper, "xmloff",
373                      "Adding duplicate family " << rStrName <<
374                      " with mismatching mapper ! " <<
375                      typeid((*iter)->mxMapper.get()).name() << " " <<
376                      typeid(*rMapper).name() );
377     }
378 #endif
379 
380     m_FamilySet.insert(std::make_unique<XMLAutoStyleFamily>(nFamily, rStrName, rMapper, aPrefix, bAsFamily));
381 }
382 
SetFamilyPropSetMapper(sal_Int32 nFamily,const rtl::Reference<SvXMLExportPropertyMapper> & rMapper)383 void SvXMLAutoStylePoolP_Impl::SetFamilyPropSetMapper(
384         sal_Int32 nFamily,
385         const rtl::Reference < SvXMLExportPropertyMapper > & rMapper )
386 {
387     std::unique_ptr<XMLAutoStyleFamily> pTemp(new XMLAutoStyleFamily(nFamily));
388     auto const iter = m_FamilySet.find(pTemp);
389     if (iter != m_FamilySet.end())
390         (*iter)->mxMapper = rMapper;
391 }
392 
393 // Adds a name to list
RegisterName(sal_Int32 nFamily,const OUString & rName)394 void SvXMLAutoStylePoolP_Impl::RegisterName( sal_Int32 nFamily, const OUString& rName )
395 {
396     std::unique_ptr<XMLAutoStyleFamily> pTemp(new XMLAutoStyleFamily(nFamily));
397     auto const iter = m_FamilySet.find(pTemp);
398     assert(iter != m_FamilySet.end()); // family must be known
399     // SAL_DEBUG("SvXMLAutoStylePoolP_Impl::RegisterName: " << nFamily << ", '" << rName << "'");
400     (*iter)->maNameSet.insert(rName);
401 }
402 
403 // Adds a name to list
RegisterDefinedName(sal_Int32 nFamily,const OUString & rName)404 void SvXMLAutoStylePoolP_Impl::RegisterDefinedName( sal_Int32 nFamily, const OUString& rName )
405 {
406     std::unique_ptr<XMLAutoStyleFamily> pTemp(new XMLAutoStyleFamily(nFamily));
407     auto const iter = m_FamilySet.find(pTemp);
408     assert(iter != m_FamilySet.end()); // family must be known
409     (*iter)->maReservedNameSet.insert(rName);
410 }
411 
412 
413 // Retrieve the list of registered names
414 
415 
GetRegisteredNames(uno::Sequence<sal_Int32> & rFamilies,uno::Sequence<OUString> & rNames)416 void SvXMLAutoStylePoolP_Impl::GetRegisteredNames(
417     uno::Sequence<sal_Int32>& rFamilies,
418     uno::Sequence<OUString>& rNames )
419 {
420     // collect registered names + families
421     vector<sal_Int32> aFamilies;
422     vector<OUString> aNames;
423 
424     // iterate over families
425     for (auto const& aJ : m_FamilySet)
426     {
427         XMLAutoStyleFamily &rFamily = *aJ;
428 
429         // iterate over names
430         for (const auto& rName : rFamily.maNameSet)
431         {
432             aFamilies.push_back( rFamily.mnFamily );
433             aNames.push_back( rName );
434         }
435     }
436 
437     // copy the families + names into the sequence types
438     assert(aFamilies.size() == aNames.size());
439 
440     rFamilies.realloc( aFamilies.size() );
441     std::copy( aFamilies.begin(), aFamilies.end(), rFamilies.getArray() );
442 
443     rNames.realloc( aNames.size() );
444     std::copy( aNames.begin(), aNames.end(), rNames.getArray() );
445 }
446 
447 // Adds an array of XMLPropertyState ( vector< XMLPropertyState > ) to list
448 // if not added, yet.
449 
Add(OUString & rName,sal_Int32 nFamily,const OUString & rParentName,const::std::vector<XMLPropertyState> & rProperties,bool bDontSeek)450 bool SvXMLAutoStylePoolP_Impl::Add(
451     OUString& rName, sal_Int32 nFamily, const OUString& rParentName,
452     const ::std::vector< XMLPropertyState >& rProperties, bool bDontSeek )
453 {
454     std::unique_ptr<XMLAutoStyleFamily> pTemp(new XMLAutoStyleFamily(nFamily));
455     auto const iter = m_FamilySet.find(pTemp);
456     assert(iter != m_FamilySet.end()); // family must be known
457 
458     XMLAutoStyleFamily &rFamily = **iter;
459 
460     std::unique_ptr<XMLAutoStylePoolParent> pTmp(new XMLAutoStylePoolParent(rParentName));
461     auto itPair = rFamily.m_ParentSet.insert(std::make_unique<XMLAutoStylePoolParent>(
462                         rParentName));
463     XMLAutoStylePoolParent& rParent = **itPair.first;
464 
465     bool bRet = false;
466     if (rParent.Add(rFamily, rProperties, rName, bDontSeek))
467     {
468         rFamily.mnCount++;
469         bRet = true;
470     }
471 
472     return bRet;
473 }
474 
AddNamed(const OUString & rName,sal_Int32 nFamily,const OUString & rParentName,const::std::vector<XMLPropertyState> & rProperties)475 bool SvXMLAutoStylePoolP_Impl::AddNamed(
476     const OUString& rName, sal_Int32 nFamily, const OUString& rParentName,
477     const ::std::vector< XMLPropertyState >& rProperties )
478 {
479     // get family and parent the same way as in Add()
480 
481     std::unique_ptr<XMLAutoStyleFamily> pTemp(new XMLAutoStyleFamily(nFamily));
482     auto const iter = m_FamilySet.find(pTemp);
483     assert(iter != m_FamilySet.end());  // family must be known
484 
485     XMLAutoStyleFamily &rFamily = **iter;
486 
487     auto itPair = rFamily.m_ParentSet.insert(std::make_unique<XMLAutoStylePoolParent>(
488                         rParentName));
489     XMLAutoStylePoolParent& rParent = **itPair.first;
490 
491     bool bRet = false;
492     if (rParent.AddNamed(rFamily, rProperties, rName))
493     {
494         rFamily.mnCount++;
495         bRet = true;
496     }
497 
498     return bRet;
499 }
500 
501 
502 // Search for an array of XMLPropertyState ( vector< XMLPropertyState > ) in list
503 
504 
Find(sal_Int32 nFamily,const OUString & rParent,const vector<XMLPropertyState> & rProperties) const505 OUString SvXMLAutoStylePoolP_Impl::Find( sal_Int32 nFamily,
506                                          const OUString& rParent,
507                                          const vector< XMLPropertyState >& rProperties ) const
508 {
509     OUString sName;
510 
511     std::unique_ptr<XMLAutoStyleFamily> pTemp(new XMLAutoStyleFamily(nFamily));
512     auto const iter = m_FamilySet.find(pTemp);
513     assert(iter != m_FamilySet.end()); // family must be known
514 
515     XMLAutoStyleFamily const& rFamily = **iter;
516     std::unique_ptr<XMLAutoStylePoolParent> pTmp(new XMLAutoStylePoolParent(rParent));
517     auto const it2 = rFamily.m_ParentSet.find(pTmp);
518     if (it2 != rFamily.m_ParentSet.end())
519     {
520         sName = (*it2)->Find(rFamily, rProperties);
521     }
522 
523     return sName;
524 }
525 
GetAutoStyleEntries() const526 std::vector<xmloff::AutoStyleEntry> SvXMLAutoStylePoolP_Impl::GetAutoStyleEntries() const
527 {
528     std::vector<xmloff::AutoStyleEntry> rReturnVector;
529 
530     for (std::unique_ptr<XMLAutoStyleFamily> const & rFamily : m_FamilySet)
531     {
532         rtl::Reference<XMLPropertySetMapper> aPropertyMapper = rFamily->mxMapper->getPropertySetMapper();
533         for (auto const & rParent : rFamily->m_ParentSet)
534         {
535             for (auto const & rProperty : rParent->GetPropertiesList())
536             {
537                 rReturnVector.emplace_back();
538                 xmloff::AutoStyleEntry & rEntry = rReturnVector.back();
539                 for (XMLPropertyState const & rPropertyState : rProperty->GetProperties())
540                 {
541                     if (rPropertyState.mnIndex >= 0)
542                     {
543                         OUString sXmlName = aPropertyMapper->GetEntryXMLName(rPropertyState.mnIndex);
544                         rEntry.m_aXmlProperties.emplace_back(sXmlName, rPropertyState.maValue);
545                     }
546                 }
547             }
548         }
549     }
550     return rReturnVector;
551 }
552 
553 namespace {
554 
555 struct AutoStylePoolExport
556 {
557     const OUString* mpParent;
558     XMLAutoStylePoolProperties* mpProperties;
559 
AutoStylePoolExport__anond01bf3cb0111::AutoStylePoolExport560     AutoStylePoolExport() : mpParent(nullptr), mpProperties(nullptr) {}
561 };
562 
563 struct StyleComparator
564 {
operator ()__anond01bf3cb0111::StyleComparator565     bool operator() (const AutoStylePoolExport& a, const AutoStylePoolExport& b)
566     {
567         return (a.mpProperties->GetName() < b.mpProperties->GetName() ||
568                 (a.mpProperties->GetName() == b.mpProperties->GetName() && *a.mpParent < *b.mpParent));
569     }
570 };
571 
572 }
573 
exportXML(sal_Int32 nFamily,const SvXMLAutoStylePoolP * pAntiImpl) const574 void SvXMLAutoStylePoolP_Impl::exportXML(
575         sal_Int32 nFamily,
576         const SvXMLAutoStylePoolP *pAntiImpl) const
577 {
578     // Get list of parents for current family (nFamily)
579     std::unique_ptr<XMLAutoStyleFamily> pTemp(new XMLAutoStyleFamily(nFamily));
580     auto const iter = m_FamilySet.find(pTemp);
581     assert(iter != m_FamilySet.end()); // family must be known
582 
583     const XMLAutoStyleFamily &rFamily = **iter;
584     sal_uInt32 nCount = rFamily.mnCount;
585 
586     if (!nCount)
587         return;
588 
589     // create, initialize and fill helper-structure (SvXMLAutoStylePoolProperties_Impl)
590     // which contains a parent-name and a SvXMLAutoStylePoolProperties_Impl
591     std::vector<AutoStylePoolExport> aExpStyles(nCount);
592 
593     for (auto const& it : rFamily.m_ParentSet)
594     {
595         XMLAutoStylePoolParent& rParent = *it;
596         size_t nProperties = rParent.GetPropertiesList().size();
597         for( size_t j = 0; j < nProperties; j++ )
598         {
599             XMLAutoStylePoolProperties *const pProperties =
600                 rParent.GetPropertiesList()[j].get();
601             sal_uInt32 nPos = pProperties->GetPos();
602             assert(nPos < nCount);
603             assert(!aExpStyles[nPos].mpProperties);
604             aExpStyles[nPos].mpProperties = pProperties;
605             aExpStyles[nPos].mpParent = &rParent.GetParent();
606         }
607     }
608 
609     static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr);
610 
611     if (bHack)
612     {
613 
614         std::sort(aExpStyles.begin(), aExpStyles.end(), StyleComparator());
615 
616         for (size_t i = 0; i < nCount; i++)
617         {
618             OUString oldName = aExpStyles[i].mpProperties->GetName();
619             sal_Int32 dashIx = oldName.indexOf('-');
620             OUString newName = (dashIx > 0 ? oldName.copy(0, dashIx) : oldName) + OUString::number(i);
621             // SAL_DEBUG("renaming '" << oldName << "' -> '" << newName << "'");
622             aExpStyles[i].mpProperties->SetName(newName);
623         }
624     }
625 
626 
627     // create string to export for each XML-style. That means for each property-list
628 
629     OUString aStrFamilyName = rFamily.maStrFamilyName;
630 
631     for( size_t i = 0; i < nCount; i++ )
632     {
633         assert(aExpStyles[i].mpProperties);
634 
635         if( aExpStyles[i].mpProperties )
636         {
637             GetExport().AddAttribute(
638                 XML_NAMESPACE_STYLE, XML_NAME,
639                 aExpStyles[i].mpProperties->GetName() );
640 
641             bool bExtensionNamespace = false;
642             if( rFamily.mbAsFamily )
643             {
644                 GetExport().AddAttribute(
645                     XML_NAMESPACE_STYLE, XML_FAMILY, aStrFamilyName );
646                 if(aStrFamilyName != "graphic" &&
647                         aStrFamilyName != "drawing-page" &&
648                         aStrFamilyName != "presentation" &&
649                         aStrFamilyName != "chart" )
650                     bExtensionNamespace = true;
651             }
652 
653             if( !aExpStyles[i].mpParent->isEmpty() )
654             {
655                 GetExport().AddAttribute(
656                     XML_NAMESPACE_STYLE, XML_PARENT_STYLE_NAME,
657                     GetExport().EncodeStyleName(
658                         *aExpStyles[i].mpParent ) );
659             }
660 
661             OUString sName;
662             if( rFamily.mbAsFamily )
663                 sName = GetXMLToken(XML_STYLE);
664             else
665                 sName = rFamily.maStrFamilyName;
666 
667             pAntiImpl->exportStyleAttributes(GetExport().GetAttrList(), nFamily,
668                                              aExpStyles[i].mpProperties->GetProperties(),
669                                              *rFamily.mxMapper, GetExport().GetMM100UnitConverter(),
670                                              GetExport().GetNamespaceMap());
671 
672             SvXMLElementExport aElem( GetExport(),
673                                       XML_NAMESPACE_STYLE, sName,
674                                       true, true );
675 
676             sal_Int32 nStart(-1);
677             sal_Int32 nEnd(-1);
678             if (nFamily == XML_STYLE_FAMILY_PAGE_MASTER)
679             {
680                 nStart = 0;
681                 sal_Int32 nIndex = 0;
682                 rtl::Reference< XMLPropertySetMapper > aPropMapper =
683                     rFamily.mxMapper->getPropertySetMapper();
684                 sal_Int16 nContextID;
685                 while(nIndex < aPropMapper->GetEntryCount() && nEnd == -1)
686                 {
687                     nContextID = aPropMapper->GetEntryContextId( nIndex );
688                     if (nContextID && ((nContextID & CTF_PM_FLAGMASK) != XML_PM_CTF_START))
689                         nEnd = nIndex;
690                     nIndex++;
691                 }
692                 if (nEnd == -1)
693                     nEnd = nIndex;
694             }
695 
696             rFamily.mxMapper->exportXML(
697                 GetExport(),
698                 aExpStyles[i].mpProperties->GetProperties(),
699                 nStart, nEnd, SvXmlExportFlags::IGN_WS, bExtensionNamespace );
700 
701             pAntiImpl->exportStyleContent(GetExport().GetDocHandler(), nFamily,
702                                           aExpStyles[i].mpProperties->GetProperties(),
703                                           *rFamily.mxMapper, GetExport().GetMM100UnitConverter(),
704                                           GetExport().GetNamespaceMap());
705         }
706     }
707 }
708 
ClearEntries()709 void SvXMLAutoStylePoolP_Impl::ClearEntries()
710 {
711     for (auto & aI : m_FamilySet)
712         aI->ClearEntries();
713 }
714 
715 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
716