Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/xmloff/source/style/xmlexppr.cxx
Line
Count
Source
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 <optional>
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 <comphelper/anycompare.hxx>
31
#include <comphelper/diagnose_ex.hxx>
32
#include <cppuhelper/weakref.hxx>
33
#include <osl/diagnose.h>
34
#include <list>
35
#include <map>
36
#include <o3tl/sorted_vector.hxx>
37
38
#include <utility>
39
#include <xmloff/xmlexppr.hxx>
40
#include <xmloff/xmltoken.hxx>
41
#include <xmloff/namespacemap.hxx>
42
#include <xmloff/xmlnamespace.hxx>
43
#include <xmloff/xmlexp.hxx>
44
#include <xmloff/xmlprmap.hxx>
45
#include <xmloff/maptype.hxx>
46
#include <xmloff/xmltypes.hxx>
47
#include <xmloff/xmlprhdl.hxx>
48
49
using namespace ::com::sun::star;
50
using namespace ::com::sun::star::beans;
51
using namespace ::com::sun::star::uno;
52
using namespace ::xmloff::token;
53
54
59.3k
#define GET_PROP_TYPE( f ) static_cast<sal_uInt16>((f & XML_TYPE_PROP_MASK) >> XML_TYPE_PROP_SHIFT)
55
56
namespace {
57
58
struct XMLPropTokens_Impl
59
{
60
    sal_uInt16 nType;
61
    XMLTokenEnum eToken;
62
};
63
64
const sal_uInt16 MAX_PROP_TYPES =
65
    (XML_TYPE_PROP_END >> XML_TYPE_PROP_SHIFT) -
66
    (XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT);
67
68
XMLPropTokens_Impl const aPropTokens[MAX_PROP_TYPES] =
69
{
70
    { GET_PROP_TYPE(XML_TYPE_PROP_CHART), XML_CHART_PROPERTIES },
71
    { GET_PROP_TYPE(XML_TYPE_PROP_GRAPHIC), XML_GRAPHIC_PROPERTIES },
72
    { GET_PROP_TYPE(XML_TYPE_PROP_TABLE), XML_TABLE_PROPERTIES },
73
    { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_COLUMN), XML_TABLE_COLUMN_PROPERTIES },
74
    { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_ROW), XML_TABLE_ROW_PROPERTIES },
75
    { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_CELL), XML_TABLE_CELL_PROPERTIES },
76
    { GET_PROP_TYPE(XML_TYPE_PROP_LIST_LEVEL), XML_LIST_LEVEL_PROPERTIES },
77
    { GET_PROP_TYPE(XML_TYPE_PROP_PARAGRAPH), XML_PARAGRAPH_PROPERTIES },
78
    { GET_PROP_TYPE(XML_TYPE_PROP_TEXT), XML_TEXT_PROPERTIES },
79
    { GET_PROP_TYPE(XML_TYPE_PROP_DRAWING_PAGE), XML_DRAWING_PAGE_PROPERTIES },
80
    { GET_PROP_TYPE(XML_TYPE_PROP_PAGE_LAYOUT), XML_PAGE_LAYOUT_PROPERTIES },
81
    { GET_PROP_TYPE(XML_TYPE_PROP_HEADER_FOOTER), XML_HEADER_FOOTER_PROPERTIES },
82
    { GET_PROP_TYPE(XML_TYPE_PROP_RUBY), XML_RUBY_PROPERTIES },
83
    { GET_PROP_TYPE(XML_TYPE_PROP_SECTION), XML_SECTION_PROPERTIES }
84
};
85
86
// public methods
87
88
// Take all properties of the XPropertySet which are also found in the
89
// XMLPropertyMapEntry-array and which are not set to their default-value,
90
// if a state is available.
91
// After that I call the method 'ContextFilter'.
92
93
struct ComparePropertyState
94
{
95
    bool operator()(XMLPropertyState const& lhs, XMLPropertyState const& rhs)
96
895k
    {
97
895k
        return lhs.mnIndex < rhs.mnIndex;
98
895k
    }
99
};
100
class XMLPropertyStates_Impl
101
{
102
    o3tl::sorted_vector<XMLPropertyState, ComparePropertyState> aPropStates;
103
public:
104
    XMLPropertyStates_Impl();
105
    void AddPropertyState(const XMLPropertyState& rPropState);
106
    void FillPropertyStateVector(std::vector<XMLPropertyState>& rVector);
107
};
108
109
XMLPropertyStates_Impl::XMLPropertyStates_Impl()
110
15.6k
{
111
15.6k
}
112
113
void XMLPropertyStates_Impl::AddPropertyState(
114
        const XMLPropertyState& rPropState)
115
200k
{
116
200k
    aPropStates.insert(rPropState);
117
200k
}
118
119
void XMLPropertyStates_Impl::FillPropertyStateVector(
120
        std::vector<XMLPropertyState>& rVector)
121
15.6k
{
122
15.6k
    rVector.insert( rVector.begin(), aPropStates.begin(), aPropStates.end() );
123
15.6k
}
124
125
class FilterPropertyInfo_Impl
126
{
127
    OUString                msApiName;
128
    std::vector<sal_uInt32> maIndexes;
129
130
public:
131
132
    FilterPropertyInfo_Impl( OUString aApiName,
133
                             const sal_uInt32 nIndex);
134
135
887k
    const OUString& GetApiName() const { return msApiName; }
136
229k
    std::vector<sal_uInt32>& GetIndexes() { return maIndexes; }
137
138
    // for sort
139
    bool operator< ( const FilterPropertyInfo_Impl& rArg ) const
140
287k
    {
141
287k
        return (GetApiName() < rArg.GetApiName());
142
287k
    }
143
};
144
145
FilterPropertyInfo_Impl::FilterPropertyInfo_Impl(
146
        OUString aApiName,
147
        const sal_uInt32 nIndex ) :
148
54.1k
    msApiName(std::move( aApiName ))
149
54.1k
{
150
54.1k
    maIndexes.push_back(nIndex);
151
54.1k
}
152
153
typedef std::list<FilterPropertyInfo_Impl> FilterPropertyInfoList_Impl;
154
155
class FilterPropertiesInfo_Impl
156
{
157
    FilterPropertyInfoList_Impl             aPropInfos;
158
159
    std::optional<Sequence<OUString>>     mxApiNames;
160
161
public:
162
    FilterPropertiesInfo_Impl();
163
164
    void AddProperty(const OUString& rApiName, const sal_uInt32 nIndex);
165
    const uno::Sequence<OUString>& GetApiNames();
166
    void FillPropertyStateArray(
167
            std::vector< XMLPropertyState >& rPropStates,
168
            const Reference< XPropertySet >& xPropSet,
169
            const rtl::Reference< XMLPropertySetMapper >& maPropMapper,
170
            const bool bDefault);
171
15.6k
    sal_uInt32 GetPropertyCount() const { return aPropInfos.size(); }
172
};
173
174
FilterPropertiesInfo_Impl::FilterPropertiesInfo_Impl()
175
532
{
176
532
}
177
178
void FilterPropertiesInfo_Impl::AddProperty(
179
        const OUString& rApiName, const sal_uInt32 nIndex)
180
54.1k
{
181
54.1k
    aPropInfos.emplace_back(rApiName, nIndex);
182
183
54.1k
    OSL_ENSURE( !mxApiNames, "performance warning: API names already retrieved" );
184
54.1k
    mxApiNames.reset();
185
54.1k
}
186
187
const uno::Sequence<OUString>& FilterPropertiesInfo_Impl::GetApiNames()
188
15.6k
{
189
15.6k
    if( !mxApiNames )
190
532
    {
191
        // we have to do three things:
192
        // 1) sort API names,
193
        // 2) merge duplicates,
194
        // 3) construct sequence
195
196
        // sort names
197
532
        aPropInfos.sort();
198
199
        // merge duplicates
200
532
        if ( aPropInfos.size() > 1 )
201
455
        {
202
455
            FilterPropertyInfoList_Impl::iterator aOld = aPropInfos.begin();
203
455
            FilterPropertyInfoList_Impl::iterator aEnd = aPropInfos.end();
204
455
            FilterPropertyInfoList_Impl::iterator aCurrent = aOld;
205
455
            ++aCurrent;
206
207
54.1k
            while ( aCurrent != aEnd )
208
53.6k
            {
209
                // equal to next element?
210
53.6k
                if ( aOld->GetApiName() == aCurrent->GetApiName() )
211
10.1k
                {
212
                    // if equal: merge index lists
213
10.1k
                    std::vector<sal_uInt32> aMerged;
214
10.1k
                    std::merge(aOld->GetIndexes().begin(), aOld->GetIndexes().end(),
215
10.1k
                               aCurrent->GetIndexes().begin(), aCurrent->GetIndexes().end(),
216
10.1k
                               std::back_inserter(aMerged));
217
10.1k
                    aOld->GetIndexes() = std::move(aMerged);
218
10.1k
                    aCurrent->GetIndexes().clear();
219
                    // erase element, and continue with next
220
10.1k
                    aCurrent = aPropInfos.erase( aCurrent );
221
10.1k
                }
222
43.5k
                else
223
43.5k
                {
224
                    // remember old element and continue with next
225
43.5k
                    aOld = aCurrent;
226
43.5k
                    ++aCurrent;
227
43.5k
                }
228
53.6k
            }
229
455
        }
230
231
        // construct sequence
232
532
        mxApiNames.emplace( aPropInfos.size() );
233
532
        OUString *pNames = mxApiNames->getArray();
234
235
532
        for (auto const& propInfo : aPropInfos)
236
44.0k
        {
237
44.0k
            *pNames = propInfo.GetApiName();
238
44.0k
            ++pNames;
239
44.0k
        }
240
532
    }
241
242
15.6k
    return *mxApiNames;
243
15.6k
}
244
245
void FilterPropertiesInfo_Impl::FillPropertyStateArray(
246
        std::vector< XMLPropertyState >& rPropStates,
247
        const Reference< XPropertySet >& rPropSet,
248
        const rtl::Reference< XMLPropertySetMapper >& rPropMapper,
249
        const bool bDefault )
250
15.6k
{
251
15.6k
    XMLPropertyStates_Impl aPropStates;
252
253
15.6k
    const uno::Sequence<OUString>& rApiNames = GetApiNames();
254
255
15.6k
    Reference < XTolerantMultiPropertySet > xTolPropSet( rPropSet, UNO_QUERY );
256
15.6k
    if (xTolPropSet.is())
257
0
    {
258
0
        if (!bDefault)
259
0
        {
260
0
            Sequence < beans::GetDirectPropertyTolerantResult > aResults(xTolPropSet->getDirectPropertyValuesTolerant(rApiNames));
261
0
            sal_Int32 nResultCount(aResults.getLength());
262
0
            if (nResultCount > 0)
263
0
            {
264
0
                const beans::GetDirectPropertyTolerantResult *pResults = aResults.getConstArray();
265
0
                FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin());
266
0
                XMLPropertyState aNewProperty( -1 );
267
0
                while (nResultCount > 0 && aPropIter != aPropInfos.end())
268
0
                {
269
0
                    if (pResults->Name == aPropIter->GetApiName())
270
0
                    {
271
0
                        aNewProperty.mnIndex = -1;
272
0
                        aNewProperty.maValue = pResults->Value;
273
274
0
                        for (auto const& index : aPropIter->GetIndexes())
275
0
                        {
276
0
                            aNewProperty.mnIndex = index;
277
0
                            aPropStates.AddPropertyState( aNewProperty );
278
0
                        }
279
0
                        ++pResults;
280
0
                        --nResultCount;
281
0
                    }
282
0
                    ++aPropIter;
283
0
                }
284
0
            }
285
0
        }
286
0
        else
287
0
        {
288
0
            const Sequence < beans::GetPropertyTolerantResult > aResults(xTolPropSet->getPropertyValuesTolerant(rApiNames));
289
0
            OSL_ENSURE( rApiNames.getLength() == aResults.getLength(), "wrong implemented XTolerantMultiPropertySet" );
290
0
            FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin());
291
0
            XMLPropertyState aNewProperty( -1 );
292
0
            OSL_ENSURE( aPropInfos.size() == static_cast<sal_uInt32>(aResults.getLength()), "wrong implemented XTolerantMultiPropertySet??" );
293
0
            for( const auto& rResult : aResults )
294
0
            {
295
0
                if ((rResult.Result == beans::TolerantPropertySetResultType::SUCCESS) &&
296
0
                    ((rResult.State == PropertyState_DIRECT_VALUE) || (rResult.State == PropertyState_DEFAULT_VALUE)))
297
0
                {
298
0
                    aNewProperty.mnIndex = -1;
299
0
                    aNewProperty.maValue = rResult.Value;
300
301
0
                    for (auto const& index : aPropIter->GetIndexes())
302
0
                    {
303
0
                        aNewProperty.mnIndex = index;
304
0
                        aPropStates.AddPropertyState( aNewProperty );
305
0
                    }
306
0
                }
307
0
                ++aPropIter;
308
0
            }
309
0
        }
310
0
    }
311
15.6k
    else
312
15.6k
    {
313
15.6k
        Sequence < PropertyState > aStates;
314
15.6k
        const PropertyState *pStates = nullptr;
315
15.6k
        Reference< XPropertyState > xPropState( rPropSet, UNO_QUERY );
316
15.6k
        if( xPropState.is() )
317
15.4k
        {
318
15.4k
            aStates = xPropState->getPropertyStates( rApiNames );
319
15.4k
            pStates = aStates.getConstArray();
320
15.4k
        }
321
322
15.6k
        Reference < XMultiPropertySet > xMultiPropSet( rPropSet, UNO_QUERY );
323
15.6k
        if( xMultiPropSet.is() && !bDefault )
324
15.5k
        {
325
15.5k
            Sequence < Any > aValues;
326
15.5k
            if( pStates )
327
15.3k
            {
328
                // step 1: get value count
329
15.3k
                sal_uInt32 nValueCount = 0;
330
331
1.39M
                for (size_t i = 0; i < aPropInfos.size(); ++i, ++pStates)
332
1.38M
                {
333
1.38M
                    if( *pStates == PropertyState_DIRECT_VALUE )
334
159k
                        nValueCount++;
335
1.38M
                }
336
337
15.3k
                if( nValueCount )
338
7.94k
                {
339
                    // step 2: collect property names
340
7.94k
                    Sequence < OUString > aAPINames( nValueCount );
341
7.94k
                    OUString *pAPINames = aAPINames.getArray();
342
343
7.94k
                    ::std::vector< FilterPropertyInfoList_Impl::iterator > aPropIters;
344
7.94k
                    aPropIters.reserve( nValueCount );
345
346
7.94k
                    FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
347
7.94k
                    OSL_ENSURE(aItr != aPropInfos.end(),"Invalid iterator!");
348
349
7.94k
                    pStates = aStates.getConstArray();
350
7.94k
                    sal_uInt32 i = 0;
351
670k
                    while( i < nValueCount )
352
663k
                    {
353
663k
                        if( *pStates == PropertyState_DIRECT_VALUE )
354
159k
                        {
355
159k
                            *pAPINames++ = aItr->GetApiName();
356
159k
                            aPropIters.push_back( aItr );
357
159k
                            ++i;
358
159k
                        }
359
663k
                        ++aItr;
360
663k
                        ++pStates;
361
663k
                    }
362
363
7.94k
                    aValues = xMultiPropSet->getPropertyValues( aAPINames );
364
7.94k
                    const Any *pValues = aValues.getConstArray();
365
366
7.94k
                    ::std::vector< FilterPropertyInfoList_Impl::iterator >::const_iterator
367
7.94k
                        pPropIter = aPropIters.begin();
368
369
7.94k
                    XMLPropertyState aNewProperty( -1 );
370
167k
                    for( i = 0; i < nValueCount; ++i )
371
159k
                    {
372
159k
                        aNewProperty.mnIndex = -1;
373
159k
                        aNewProperty.maValue = *pValues;
374
375
159k
                        for (auto const& index : (*pPropIter)->GetIndexes())
376
197k
                        {
377
197k
                            aNewProperty.mnIndex = index;
378
197k
                            aPropStates.AddPropertyState( aNewProperty );
379
197k
                        }
380
381
159k
                        ++pPropIter;
382
159k
                        ++pValues;
383
159k
                    }
384
7.94k
                }
385
15.3k
            }
386
237
            else
387
237
            {
388
237
                aValues = xMultiPropSet->getPropertyValues( rApiNames );
389
237
                const Any *pValues = aValues.getConstArray();
390
391
237
                FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
392
474
                for (size_t i = 0; i < aPropInfos.size(); ++i)
393
237
                {
394
                    // The value is stored in the PropertySet itself, add to list.
395
237
                    XMLPropertyState aNewProperty( -1 );
396
237
                    aNewProperty.maValue = *pValues;
397
237
                    ++pValues;
398
237
                    for (auto const& index : aItr->GetIndexes())
399
237
                    {
400
237
                        aNewProperty.mnIndex = index;
401
237
                        aPropStates.AddPropertyState( aNewProperty );
402
237
                    }
403
237
                    ++aItr;
404
237
                }
405
237
            }
406
15.5k
        }
407
126
        else
408
126
        {
409
126
            FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
410
10.2k
            for (size_t i = 0; i < aPropInfos.size(); ++i)
411
10.1k
            {
412
10.1k
                bool bDirectValue =
413
10.1k
                    !pStates || *pStates == PropertyState_DIRECT_VALUE;
414
10.1k
                if( bDirectValue || bDefault )
415
8.85k
                {
416
                    // The value is stored in the PropertySet itself, add to list.
417
8.85k
                    bool bGotValue = false;
418
8.85k
                    XMLPropertyState aNewProperty( -1 );
419
8.85k
                    for (auto const& index : aItr->GetIndexes())
420
10.3k
                    {
421
10.3k
                        if( bDirectValue ||
422
8.86k
                            (rPropMapper->GetEntryFlags(index) &
423
8.86k
                                            MID_FLAG_DEFAULT_ITEM_EXPORT) != 0 )
424
2.53k
                        {
425
2.53k
                            try
426
2.53k
                            {
427
2.53k
                                if( !bGotValue )
428
1.89k
                                {
429
1.89k
                                    aNewProperty.maValue =
430
1.89k
                                        rPropSet->getPropertyValue( aItr->GetApiName() );
431
1.89k
                                    bGotValue = true;
432
1.89k
                                }
433
2.53k
                                aNewProperty.mnIndex = index;
434
2.53k
                                aPropStates.AddPropertyState( aNewProperty );
435
2.53k
                            }
436
2.53k
                            catch( UnknownPropertyException& )
437
2.53k
                            {
438
                                // might be a problem of getImplementationId
439
0
                                TOOLS_WARN_EXCEPTION("xmloff.style", "unknown property in getPropertyValue" );
440
0
                            }
441
442
2.53k
                        }
443
10.3k
                    }
444
8.85k
                }
445
446
10.1k
                ++aItr;
447
10.1k
                if( pStates )
448
10.1k
                    ++pStates;
449
10.1k
            }
450
126
        }
451
15.6k
    }
452
15.6k
    aPropStates.FillPropertyStateVector(rPropStates);
453
15.6k
}
454
455
}
456
457
struct SvXMLExportPropertyMapper::Impl
458
{
459
    typedef std::map<css::uno::Reference<css::beans::XPropertySetInfo>, std::unique_ptr<FilterPropertiesInfo_Impl>> CacheType;
460
    CacheType maCache;
461
462
    rtl::Reference<SvXMLExportPropertyMapper> mxNextMapper;
463
    rtl::Reference<XMLPropertySetMapper> mxPropMapper;
464
465
    OUString maStyleName;
466
};
467
468
// ctor/dtor , class SvXMLExportPropertyMapper
469
470
SvXMLExportPropertyMapper::SvXMLExportPropertyMapper(
471
        const rtl::Reference< XMLPropertySetMapper >& rMapper ) :
472
1.37k
    mpImpl(new Impl)
473
1.37k
{
474
1.37k
    mpImpl->mxPropMapper = rMapper;
475
1.37k
}
476
477
SvXMLExportPropertyMapper::~SvXMLExportPropertyMapper()
478
1.37k
{
479
1.37k
}
480
481
void SvXMLExportPropertyMapper::ChainExportMapper(
482
        const rtl::Reference< SvXMLExportPropertyMapper>& rMapper )
483
329
{
484
    // add map entries from rMapper to current map
485
329
    mpImpl->mxPropMapper->AddMapperEntry( rMapper->getPropertySetMapper() );
486
    // rMapper uses the same map as 'this'
487
329
    rMapper->mpImpl->mxPropMapper = mpImpl->mxPropMapper;
488
489
    // set rMapper as last mapper in current chain
490
329
    rtl::Reference< SvXMLExportPropertyMapper > xNext = mpImpl->mxNextMapper;
491
329
    if( xNext.is())
492
126
    {
493
126
        while (xNext->mpImpl->mxNextMapper.is())
494
0
            xNext = xNext->mpImpl->mxNextMapper;
495
126
        xNext->mpImpl->mxNextMapper = rMapper;
496
126
    }
497
203
    else
498
203
        mpImpl->mxNextMapper = rMapper;
499
500
    // if rMapper was already chained, correct
501
    // map pointer of successors
502
329
    xNext = rMapper;
503
504
329
    while (xNext->mpImpl->mxNextMapper.is())
505
0
    {
506
0
        xNext = xNext->mpImpl->mxNextMapper;
507
0
        xNext->mpImpl->mxPropMapper = mpImpl->mxPropMapper;
508
0
    }
509
329
}
510
511
std::vector<XMLPropertyState> SvXMLExportPropertyMapper::Filter(
512
    SvXMLExport const& rExport,
513
    const uno::Reference<beans::XPropertySet>& rPropSet, bool bEnableFoFontFamily ) const
514
15.6k
{
515
15.6k
    return Filter_(rExport, rPropSet, false, bEnableFoFontFamily);
516
15.6k
}
517
518
std::vector<XMLPropertyState> SvXMLExportPropertyMapper::FilterDefaults(
519
    SvXMLExport const& rExport,
520
    const uno::Reference<beans::XPropertySet>& rPropSet ) const
521
49
{
522
49
    return Filter_(rExport, rPropSet, true, false/*bEnableFoFontFamily*/);
523
49
}
524
525
std::vector<XMLPropertyState> SvXMLExportPropertyMapper::Filter_(
526
    SvXMLExport const& rExport,
527
    const Reference<XPropertySet>& xPropSet, bool bDefault, bool bEnableFoFontFamily ) const
528
15.6k
{
529
15.6k
    std::vector< XMLPropertyState > aPropStateArray;
530
531
    // Retrieve XPropertySetInfo and XPropertyState
532
15.6k
    Reference< XPropertySetInfo > xInfo( xPropSet->getPropertySetInfo() );
533
15.6k
    if( !xInfo.is() )
534
0
        return aPropStateArray;
535
536
15.6k
    sal_Int32 nProps = mpImpl->mxPropMapper->GetEntryCount();
537
538
15.6k
    FilterPropertiesInfo_Impl *pFilterInfo = nullptr;
539
540
15.6k
    Impl::CacheType::iterator aIter = mpImpl->maCache.find(xInfo);
541
15.6k
    if (aIter != mpImpl->maCache.end())
542
15.1k
        pFilterInfo = (*aIter).second.get();
543
544
15.6k
    bool bDelInfo = false;
545
15.6k
    if( !pFilterInfo )
546
532
    {
547
532
        assert(GetODFDefaultVersion() != SvtSaveOptions::ODFVER_UNKNOWN);
548
532
        const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(rExport.getSaneDefaultVersion());
549
532
        pFilterInfo = new FilterPropertiesInfo_Impl;
550
101k
        for( sal_Int32 i=0; i < nProps; i++ )
551
101k
        {
552
            // Are we allowed to ask for the property? (MID_FLAG_NO_PROP..)
553
            // Does the PropertySet contain name of mpEntries-array ?
554
101k
            const OUString& rAPIName = mpImpl->mxPropMapper->GetEntryAPIName( i );
555
101k
            const sal_Int32 nFlags = mpImpl->mxPropMapper->GetEntryFlags( i );
556
101k
            if( (0 == (nFlags & MID_FLAG_NO_PROPERTY_EXPORT)) &&
557
100k
                ( (0 != (nFlags & MID_FLAG_MUST_EXIST)) ||
558
100k
                  xInfo->hasPropertyByName( rAPIName ) ) )
559
54.1k
            {
560
54.1k
                const SvtSaveOptions::ODFSaneDefaultVersion nEarliestODFVersionForExport(
561
54.1k
                        mpImpl->mxPropMapper->GetEarliestODFVersionForExport(i));
562
                // note: only standard ODF versions are allowed here,
563
                // only exception is the unknown future
564
54.1k
                assert((nEarliestODFVersionForExport & SvtSaveOptions::ODFSVER_EXTENDED) == 0
565
54.1k
                    || nEarliestODFVersionForExport == SvtSaveOptions::ODFSVER_FUTURE_EXTENDED);
566
54.1k
                static_assert(SvtSaveOptions::ODFSVER_LATEST_EXTENDED < SvtSaveOptions::ODFSVER_FUTURE_EXTENDED);
567
                /// standard ODF namespaces for elements and attributes
568
54.1k
                static const sal_uInt16 s_OdfNs[] = {
569
54.1k
                    XML_NAMESPACE_OFFICE,
570
54.1k
                    XML_NAMESPACE_STYLE,
571
54.1k
                    XML_NAMESPACE_TEXT,
572
54.1k
                    XML_NAMESPACE_TABLE,
573
54.1k
                    XML_NAMESPACE_DRAW,
574
54.1k
                    XML_NAMESPACE_FO,
575
54.1k
                    XML_NAMESPACE_XLINK,
576
54.1k
                    XML_NAMESPACE_DC,
577
54.1k
                    XML_NAMESPACE_META,
578
54.1k
                    XML_NAMESPACE_NUMBER,
579
54.1k
                    XML_NAMESPACE_PRESENTATION,
580
54.1k
                    XML_NAMESPACE_SVG,
581
54.1k
                    XML_NAMESPACE_CHART,
582
54.1k
                    XML_NAMESPACE_DR3D,
583
54.1k
                    XML_NAMESPACE_MATH,
584
54.1k
                    XML_NAMESPACE_FORM,
585
54.1k
                    XML_NAMESPACE_SCRIPT,
586
54.1k
                    XML_NAMESPACE_CONFIG,
587
54.1k
                    XML_NAMESPACE_DB,
588
54.1k
                    XML_NAMESPACE_XFORMS,
589
54.1k
                    XML_NAMESPACE_SMIL,
590
54.1k
                    XML_NAMESPACE_ANIMATION,
591
54.1k
                    XML_NAMESPACE_XML,
592
54.1k
                    XML_NAMESPACE_XHTML,
593
54.1k
                    XML_NAMESPACE_GRDDL,
594
54.1k
                };
595
54.1k
                static bool s_Assert(false);
596
54.1k
                if (!s_Assert)
597
1
                {
598
1
                    assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs)));
599
1
                    s_Assert = true;
600
1
                }
601
                //static_assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs)));
602
54.1k
                auto const ns(mpImpl->mxPropMapper->GetEntryNameSpace(i));
603
54.1k
                auto const iter(std::lower_bound(std::begin(s_OdfNs), std::end(s_OdfNs),
604
54.1k
                            ns));
605
54.1k
                bool const isExtension(iter == std::end(s_OdfNs) || *iter != ns
606
                        // FIXME: very special hack to suppress style:hyperlink
607
45.9k
                        || (ns == XML_NAMESPACE_STYLE
608
21.1k
                            && mpImpl->mxPropMapper->GetEntryXMLName(i) == GetXMLToken(XML_HYPERLINK)));
609
54.1k
                if (isExtension
610
54.1k
                    ? ((nCurrentVersion & SvtSaveOptions::ODFSVER_EXTENDED)
611
                        // if it's in standard ODF, don't export extension
612
8.19k
                        && (nCurrentVersion < nEarliestODFVersionForExport))
613
54.1k
                    : (nEarliestODFVersionForExport <= nCurrentVersion))
614
54.1k
                {
615
54.1k
                    pFilterInfo->AddProperty(rAPIName, i);
616
54.1k
                }
617
54.1k
            }
618
101k
        }
619
620
        // Check whether the property set info is destroyed if it is assigned to
621
        // a weak reference only; If it is destroyed, then every instance of
622
        // getPropertySetInfo returns a new object; such property set infos must
623
        // not be cached:
624
532
        WeakReference < XPropertySetInfo > xWeakInfo( xInfo );
625
532
        xInfo.clear();
626
532
        xInfo = xWeakInfo;
627
532
        if( xInfo.is() )
628
532
        {
629
532
            mpImpl->maCache.emplace(xInfo, std::unique_ptr<FilterPropertiesInfo_Impl>(pFilterInfo));
630
532
        }
631
0
        else
632
0
            bDelInfo = true;
633
532
    }
634
635
15.6k
    if( pFilterInfo->GetPropertyCount() )
636
15.6k
    {
637
15.6k
        try
638
15.6k
        {
639
15.6k
            pFilterInfo->FillPropertyStateArray(
640
15.6k
                aPropStateArray, xPropSet, mpImpl->mxPropMapper, bDefault);
641
15.6k
        }
642
15.6k
        catch( UnknownPropertyException& )
643
15.6k
        {
644
            // might be a problem of getImplementationId
645
0
            TOOLS_WARN_EXCEPTION("xmloff.style", "unknown property in getPropertyStates" );
646
0
        }
647
15.6k
    }
648
649
    // Call context-filter
650
15.6k
    if( !aPropStateArray.empty() )
651
8.30k
        ContextFilter(bEnableFoFontFamily, aPropStateArray, xPropSet);
652
653
    // Have to do if we change from a vector to a list or something like that
654
655
15.6k
    if( bDelInfo )
656
0
        delete pFilterInfo;
657
658
15.6k
    return aPropStateArray;
659
15.6k
}
660
661
void SvXMLExportPropertyMapper::ContextFilter(
662
        bool bEnableFoFontFamily,
663
        std::vector< XMLPropertyState >& rProperties,
664
        const Reference< XPropertySet >& rPropSet ) const
665
11.0k
{
666
    // Derived class could implement this.
667
11.0k
    if (mpImpl->mxNextMapper.is())
668
2.74k
        mpImpl->mxNextMapper->ContextFilter(bEnableFoFontFamily, rProperties, rPropSet);
669
11.0k
}
670
671
// Compares two Sequences of XMLPropertyState:
672
//  1.Number of elements equal ?
673
//  2.Index of each element equal ? (So I know whether the propertynames are the same)
674
//  3.Value of each element equal ?
675
bool SvXMLExportPropertyMapper::Equals(
676
        const std::vector< XMLPropertyState >& aProperties1,
677
        const std::vector< XMLPropertyState >& aProperties2 ) const
678
9.18k
{
679
9.18k
    if (aProperties1.size() < aProperties2.size())
680
0
        return true;
681
9.18k
    if (aProperties1.size() > aProperties2.size())
682
0
        return false;
683
684
9.18k
    sal_uInt32 nCount = aProperties1.size();
685
686
223k
    for (sal_uInt32 nIndex = 0; nIndex < nCount; ++nIndex)
687
217k
    {
688
217k
        const XMLPropertyState& rProp1 = aProperties1[ nIndex ];
689
217k
        const XMLPropertyState& rProp2 = aProperties2[ nIndex ];
690
691
        // Compare index. If equal, compare value
692
217k
        if( rProp1.mnIndex < rProp2.mnIndex )
693
0
            return true;
694
217k
        if( rProp1.mnIndex > rProp2.mnIndex )
695
0
            return false;
696
697
217k
        if( rProp1.mnIndex != -1 )
698
155k
        {
699
            // Now compare values
700
155k
            if ( (mpImpl->mxPropMapper->GetEntryType( rProp1.mnIndex ) &
701
155k
                  XML_TYPE_BUILDIN_CMP ) != 0 )
702
64.0k
            {
703
                // simple type ( binary compare )
704
64.0k
                if ( rProp1.maValue != rProp2.maValue)
705
0
                    return false;
706
64.0k
            }
707
91.8k
            else
708
91.8k
            {
709
                // complex type ( ask for compare-function )
710
91.8k
                if (!mpImpl->mxPropMapper->GetPropertyHandler(
711
91.8k
                            rProp1.mnIndex )->equals( rProp1.maValue,
712
91.8k
                                                      rProp2.maValue ))
713
2.84k
                    return false;
714
91.8k
            }
715
155k
        }
716
217k
    }
717
718
6.34k
    return true;
719
9.18k
}
720
721
// Compares two Sequences of XMLPropertyState:
722
//  1.Number of elements equal ?
723
//  2.Index of each element equal ? (So I know whether the propertynames are the same)
724
//  3.Value of each element equal ?
725
bool SvXMLExportPropertyMapper::LessPartial(
726
        const std::vector< XMLPropertyState >& aProperties1,
727
        const std::vector< XMLPropertyState >& aProperties2 ) const
728
33.6k
{
729
33.6k
    if (aProperties1.size() < aProperties2.size())
730
11.0k
        return true;
731
22.5k
    if (aProperties1.size() > aProperties2.size())
732
4.22k
        return false;
733
734
18.3k
    sal_uInt32 nCount = aProperties1.size();
735
736
479k
    for (sal_uInt32 nIndex = 0; nIndex < nCount; ++nIndex)
737
464k
    {
738
464k
        const XMLPropertyState& rProp1 = aProperties1[ nIndex ];
739
464k
        const XMLPropertyState& rProp2 = aProperties2[ nIndex ];
740
741
        // Compare index. If equal, compare value
742
464k
        if( rProp1.mnIndex < rProp2.mnIndex )
743
0
            return true;
744
464k
        if( rProp1.mnIndex > rProp2.mnIndex )
745
0
            return false;
746
747
464k
        if( rProp1.mnIndex != -1 )
748
336k
        {
749
            // Now compare values
750
336k
            if ( (mpImpl->mxPropMapper->GetEntryType( rProp1.mnIndex ) &
751
336k
                  XML_TYPE_BUILDIN_CMP ) != 0 )
752
132k
            {
753
                // simple type ( binary compare )
754
132k
                if ( comphelper::anyLess(rProp1.maValue, rProp2.maValue) )
755
2.63k
                    return true;
756
129k
                if ( comphelper::anyLess(rProp2.maValue, rProp1.maValue ) )
757
939
                    return false;
758
129k
            }
759
336k
        }
760
464k
    }
761
762
14.7k
    return false;
763
18.3k
}
764
765
/** fills the given attribute list with the items in the given set
766
void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList,
767
        const ::std::vector< XMLPropertyState >& rProperties,
768
        const SvXMLUnitConverter& rUnitConverter,
769
        const SvXMLNamespaceMap& rNamespaceMap,
770
        sal_uInt16 nFlags ) const
771
{
772
    _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap,
773
                nFlags, 0, -1, -1 );
774
}
775
776
void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList,
777
        const ::std::vector< XMLPropertyState >& rProperties,
778
        const SvXMLUnitConverter& rUnitConverter,
779
        const SvXMLNamespaceMap& rNamespaceMap,
780
        sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx,
781
        sal_uInt16 nFlags ) const
782
{
783
    _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap,
784
                nFlags, 0, nPropMapStartIdx, nPropMapEndIdx );
785
}
786
*/
787
788
void SvXMLExportPropertyMapper::exportXML(
789
        SvXMLExport& rExport,
790
        const ::std::vector< XMLPropertyState >& rProperties,
791
        SvXmlExportFlags nFlags,
792
        bool bUseExtensionNamespaceForGraphicProperties) const
793
1.37k
{
794
1.37k
    exportXML(rExport, rProperties, -1, -1,  nFlags, bUseExtensionNamespaceForGraphicProperties);
795
1.37k
}
796
797
798
void SvXMLExportPropertyMapper::exportXML(
799
        SvXMLExport& rExport,
800
        const ::std::vector< XMLPropertyState >& rProperties,
801
        sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx,
802
        SvXmlExportFlags nFlags, bool bUseExtensionNamespaceForGraphicProperties) const
803
1.88k
{
804
1.88k
    sal_uInt16 nPropTypeFlags = 0;
805
28.3k
    for( sal_uInt16 i=0; i<MAX_PROP_TYPES; ++i )
806
26.4k
    {
807
26.4k
        sal_uInt16 nPropType = aPropTokens[i].nType;
808
26.4k
        if( 0==i || (nPropTypeFlags & (1 << nPropType)) != 0 )
809
4.99k
        {
810
4.99k
            sal_uInt16 nNamespace = XML_NAMESPACE_STYLE;
811
4.99k
            if (bUseExtensionNamespaceForGraphicProperties &&
812
660
                aPropTokens[i].eToken == xmloff::token::XML_GRAPHIC_PROPERTIES)
813
152
            {
814
152
                nNamespace = XML_NAMESPACE_LO_EXT;
815
152
                if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
816
0
                {
817
0
                    continue; // don't write for ODF <= 1.2
818
0
                }
819
152
            }
820
821
4.99k
            std::vector<sal_uInt16> aIndexArray;
822
823
4.99k
            _exportXML( nPropType, nPropTypeFlags,
824
4.99k
                        rExport.GetAttrList(), rProperties,
825
4.99k
                        rExport.GetMM100UnitConverter(),
826
4.99k
                        rExport.GetNamespaceMap(),
827
4.99k
                        &aIndexArray,
828
4.99k
                        nPropMapStartIdx, nPropMapEndIdx );
829
830
4.99k
            if( rExport.GetAttrList().getLength() > 0 ||
831
1.93k
                !aIndexArray.empty() )
832
3.06k
            {
833
3.06k
                SvXMLElementExport aElem( rExport, nNamespace,
834
3.06k
                                  aPropTokens[i].eToken,
835
3.06k
                                  bool(nFlags & SvXmlExportFlags::IGN_WS),
836
3.06k
                                  false );
837
838
3.06k
                exportElementItems( rExport, rProperties, nFlags, aIndexArray );
839
3.06k
            }
840
4.99k
        }
841
26.4k
    }
842
1.88k
}
843
844
/** this method is called for every item that has the
845
    MID_FLAG_SPECIAL_ITEM_EXPORT flag set */
846
void SvXMLExportPropertyMapper::handleSpecialItem(
847
        comphelper::AttributeList& rAttrList,
848
        const XMLPropertyState& rProperty,
849
        const SvXMLUnitConverter& rUnitConverter,
850
        const SvXMLNamespaceMap& rNamespaceMap,
851
        const ::std::vector< XMLPropertyState > *pProperties,
852
        sal_uInt32 nIdx ) const
853
0
{
854
0
    if (mpImpl->mxNextMapper.is())
855
0
    {
856
0
        mpImpl->mxNextMapper->handleSpecialItem(
857
0
            rAttrList, rProperty, rUnitConverter, rNamespaceMap, pProperties, nIdx);
858
0
        return;
859
0
    }
860
    // An empty Any (e.g. unset UserDefinedAttributes / ChartUserDefinedAttributes)
861
    // or a null XNameContainer reference means there is nothing to export; this
862
    // is a normal state, not a missing-handler bug.
863
0
    if (!rProperty.maValue.hasValue()
864
0
        || rProperty.maValue.getValueTypeClass() == uno::TypeClass_INTERFACE)
865
0
        return;
866
0
    SAL_WARN("xmloff.style",
867
0
             "special item not handled in xml export: index=" << rProperty.mnIndex
868
0
             << " ns=" << mpImpl->mxPropMapper->GetEntryNameSpace(rProperty.mnIndex)
869
0
             << " xmlName=" << mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex)
870
0
             << " apiName=" << mpImpl->mxPropMapper->GetEntryAPIName(rProperty.mnIndex));
871
0
}
872
873
/** this method is called for every item that has the
874
    MID_FLAG_ELEMENT_EXPORT flag set */
875
void SvXMLExportPropertyMapper::handleElementItem(
876
        SvXMLExport& rExport,
877
        const XMLPropertyState& rProperty,
878
        SvXmlExportFlags nFlags,
879
        const ::std::vector< XMLPropertyState > *pProperties,
880
        sal_uInt32 nIdx ) const
881
802
{
882
802
    OSL_ENSURE(mpImpl->mxNextMapper.is(), "element item not handled in xml export");
883
802
    if (mpImpl->mxNextMapper.is())
884
802
        mpImpl->mxNextMapper->handleElementItem(rExport, rProperty, nFlags, pProperties, nIdx);
885
802
}
886
887
// protected methods
888
889
/** fills the given attribute list with the items in the given set */
890
void SvXMLExportPropertyMapper::_exportXML(
891
        sal_uInt16 nPropType, sal_uInt16& rPropTypeFlags,
892
        comphelper::AttributeList& rAttrList,
893
        const ::std::vector< XMLPropertyState >& rProperties,
894
        const SvXMLUnitConverter& rUnitConverter,
895
        const SvXMLNamespaceMap& rNamespaceMap,
896
        std::vector<sal_uInt16>* pIndexArray,
897
        sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx ) const
898
4.99k
{
899
4.99k
    const sal_uInt32 nCount = rProperties.size();
900
4.99k
    sal_uInt32 nIndex = 0;
901
902
4.99k
    if( -1 == nPropMapStartIdx )
903
4.99k
        nPropMapStartIdx = 0;
904
4.99k
    if( -1 == nPropMapEndIdx )
905
4.99k
        nPropMapEndIdx = mpImpl->mxPropMapper->GetEntryCount();
906
907
78.5k
    while( nIndex < nCount )
908
73.5k
    {
909
73.5k
        sal_Int32 nPropMapIdx = rProperties[nIndex].mnIndex;
910
73.5k
        if( nPropMapIdx >= nPropMapStartIdx &&
911
59.3k
            nPropMapIdx < nPropMapEndIdx  )// valid entry?
912
59.3k
        {
913
59.3k
            sal_uInt32 nEFlags = mpImpl->mxPropMapper->GetEntryFlags(nPropMapIdx);
914
59.3k
            sal_uInt16 nEPType = GET_PROP_TYPE(nEFlags);
915
59.3k
            OSL_ENSURE(nEPType >= (XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT),
916
59.3k
                       "no prop type specified");
917
59.3k
            rPropTypeFlags |= (1 << nEPType);
918
59.3k
            if( nEPType == nPropType )
919
19.9k
            {
920
                // we have a valid map entry here, so let's use it...
921
19.9k
                if( ( nEFlags & MID_FLAG_ELEMENT_ITEM_EXPORT ) != 0 )
922
953
                {
923
                    // element items do not add any properties,
924
                    // we export it later
925
953
                    if( pIndexArray )
926
953
                    {
927
953
                        pIndexArray->push_back( static_cast<sal_uInt16>(nIndex) );
928
953
                    }
929
953
                }
930
19.0k
                else
931
19.0k
                {
932
19.0k
                    _exportXML( rAttrList, rProperties[nIndex], rUnitConverter,
933
19.0k
                                rNamespaceMap, &rProperties, nIndex );
934
19.0k
                }
935
19.9k
            }
936
59.3k
        }
937
938
73.5k
        nIndex++;
939
73.5k
    }
940
4.99k
}
941
942
namespace
943
{
944
// -1 = Attribute needs extended namespace, but current ODF version is strict.
945
// 1 = Attribute needs extended namespace and current ODF version allows it.
946
// 0 = Attribute does not need extended namespace
947
sal_Int8 CheckExtendedNamespace(std::u16string_view sXMLAttributeName, std::u16string_view sValue,
948
                                const SvtSaveOptions::ODFSaneDefaultVersion nODFVersion)
949
15.7k
{
950
15.7k
    if (IsXMLToken(sXMLAttributeName, XML_WRITING_MODE)
951
88
        && (IsXMLToken(sValue, XML_BT_LR) || IsXMLToken(sValue, XML_TB_RL90)))
952
0
        return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1;
953
15.7k
    else if (IsXMLToken(sXMLAttributeName, XML_VERTICAL_REL)
954
0
             && (IsXMLToken(sValue, XML_PAGE_CONTENT_BOTTOM)
955
0
                 || IsXMLToken(sValue, XML_PAGE_CONTENT_TOP)))
956
0
        return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1;
957
    // don't export end zones when they have the default no-limit value
958
15.7k
    else if (IsXMLToken(sXMLAttributeName, XML_HYPHENATION_ZONE_ALWAYS)
959
15.7k
        || IsXMLToken(sXMLAttributeName, XML_HYPHENATION_ZONE_COLUMN)
960
15.7k
        || IsXMLToken(sXMLAttributeName, XML_HYPHENATION_ZONE_PAGE)
961
15.7k
        || IsXMLToken(sXMLAttributeName, XML_HYPHENATION_ZONE_SPREAD))
962
0
        return IsXMLToken(sValue, XML_NO_LIMIT) ? -1 : 1;
963
    // don't export word spacing and glyph scaling when they have the default 100% value
964
15.7k
    else if (IsXMLToken(sXMLAttributeName, XML_WORD_SPACING)
965
15.7k
        || IsXMLToken(sXMLAttributeName, XML_WORD_SPACING_MINIMUM)
966
15.6k
        || IsXMLToken(sXMLAttributeName, XML_WORD_SPACING_MAXIMUM)
967
15.6k
        || IsXMLToken(sXMLAttributeName, XML_TEXT_SCALE_MINIMUM)
968
15.5k
        || IsXMLToken(sXMLAttributeName, XML_TEXT_SCALE_MAXIMUM))
969
250
    {
970
250
        static constexpr OUString s100PercentCompare( u"100%"_ustr );
971
250
        size_t nBegin = sValue.find( s100PercentCompare );
972
250
        return nBegin != std::u16string_view::npos ? -1 : 1;
973
250
    }
974
    // don't export letter spacing when they have the default 0% value
975
15.5k
    else if (IsXMLToken(sXMLAttributeName, XML_LETTER_SPACING_MINIMUM)
976
15.4k
        || IsXMLToken(sXMLAttributeName, XML_LETTER_SPACING_MAXIMUM))
977
100
    {
978
100
        static constexpr OUString sDefaultPercentCompare( u"0%"_ustr );
979
100
        size_t nBegin = sValue.find( sDefaultPercentCompare );
980
100
        return nBegin == static_cast<size_t>(0) ? -1 : 1;
981
100
    }
982
15.4k
    return 0;
983
15.7k
}
984
}
985
986
void SvXMLExportPropertyMapper::_exportXML(
987
        comphelper::AttributeList& rAttrList,
988
        const XMLPropertyState& rProperty,
989
        const SvXMLUnitConverter& rUnitConverter,
990
        const SvXMLNamespaceMap& rNamespaceMap,
991
        const ::std::vector< XMLPropertyState > *pProperties,
992
        sal_uInt32 nIdx ) const
993
19.0k
{
994
19.0k
    if ((mpImpl->mxPropMapper->GetEntryFlags(rProperty.mnIndex) & MID_FLAG_SPECIAL_ITEM_EXPORT) != 0)
995
98
    {
996
98
        uno::Reference< container::XNameContainer > xAttrContainer;
997
98
        if( (rProperty.maValue >>= xAttrContainer) && xAttrContainer.is() )
998
98
        {
999
98
            std::unique_ptr<SvXMLNamespaceMap> pNewNamespaceMap;
1000
98
            const SvXMLNamespaceMap *pNamespaceMap = &rNamespaceMap;
1001
1002
98
            const uno::Sequence< OUString > aAttribNames( xAttrContainer->getElementNames() );
1003
1004
98
            xml::AttributeData aData;
1005
98
            for( const auto& rAttribName : aAttribNames )
1006
0
            {
1007
0
                xAttrContainer->getByName( rAttribName ) >>= aData;
1008
0
                OUString sAttribName( rAttribName );
1009
1010
                // extract namespace prefix from attribute name if it exists
1011
0
                OUString sPrefix;
1012
0
                const sal_Int32 nColonPos =
1013
0
                    rAttribName.indexOf( ':' );
1014
0
                if( nColonPos != -1 )
1015
0
                    sPrefix = rAttribName.copy( 0, nColonPos );
1016
1017
0
                if( !sPrefix.isEmpty() )
1018
0
                {
1019
0
                    OUString sNamespace( aData.Namespace );
1020
1021
                    // if the prefix isn't defined yet or has another meaning,
1022
                    // we have to redefine it now.
1023
0
                    sal_uInt16 nKey = pNamespaceMap->GetKeyByPrefix( sPrefix );
1024
0
                    if( USHRT_MAX == nKey || pNamespaceMap->GetNameByKey( nKey ) != sNamespace )
1025
0
                    {
1026
0
                        bool bAddNamespace = false;
1027
0
                        if( USHRT_MAX == nKey )
1028
0
                        {
1029
                            // The prefix is unused, so it is sufficient
1030
                            // to add it to the namespace map.
1031
0
                            bAddNamespace = true;
1032
0
                        }
1033
0
                        else
1034
0
                        {
1035
                            // check if there is a prefix registered for the
1036
                            // namespace URI
1037
0
                            nKey = pNamespaceMap->GetKeyByName( sNamespace );
1038
0
                            if( XML_NAMESPACE_UNKNOWN == nKey )
1039
0
                            {
1040
                                // There is no prefix for the namespace, so
1041
                                // we have to generate one and have to add it.
1042
0
                                sal_Int32 n=0;
1043
0
                                OUString sOrigPrefix( sPrefix );
1044
0
                                do
1045
0
                                {
1046
0
                                    sPrefix = sOrigPrefix + OUString::number( ++n );
1047
0
                                    nKey = pNamespaceMap->GetKeyByPrefix( sPrefix );
1048
0
                                }
1049
0
                                while( nKey != USHRT_MAX );
1050
1051
0
                                bAddNamespace = true;
1052
0
                            }
1053
0
                            else
1054
0
                            {
1055
                                // If there is a prefix for the namespace,
1056
                                // we reuse that.
1057
0
                                sPrefix = pNamespaceMap->GetPrefixByKey( nKey );
1058
0
                            }
1059
                            // In any case, the attribute name has to be adapted.
1060
0
                            sAttribName = sPrefix + ":" + rAttribName.subView(nColonPos+1);
1061
0
                        }
1062
1063
0
                        if( bAddNamespace )
1064
0
                        {
1065
0
                            if( !pNewNamespaceMap )
1066
0
                            {
1067
0
                                pNewNamespaceMap.reset(new SvXMLNamespaceMap( rNamespaceMap ));
1068
0
                                pNamespaceMap = pNewNamespaceMap.get();
1069
0
                            }
1070
0
                            pNewNamespaceMap->Add( sPrefix, sNamespace );
1071
0
                            OUString sAttr = GetXMLToken(XML_XMLNS) + ":" + sPrefix;
1072
0
                            rAttrList.AddAttribute( sAttr, sNamespace );
1073
0
                        }
1074
0
                    }
1075
0
                }
1076
0
                OUString sOldValue( rAttrList.getValueByName( sAttribName ) );
1077
0
                OSL_ENSURE( sOldValue.isEmpty(), "alien attribute exists already" );
1078
0
                OSL_ENSURE(aData.Type == GetXMLToken(XML_CDATA), "different type to our default type which should be written out");
1079
0
                if( sOldValue.isEmpty() )
1080
0
                    rAttrList.AddAttribute( sAttribName, aData.Value );
1081
0
            }
1082
98
        }
1083
0
        else
1084
0
        {
1085
0
            handleSpecialItem( rAttrList, rProperty, rUnitConverter,
1086
0
                               rNamespaceMap, pProperties, nIdx );
1087
0
        }
1088
98
    }
1089
18.9k
    else if ((mpImpl->mxPropMapper->GetEntryFlags(rProperty.mnIndex) & MID_FLAG_ELEMENT_ITEM_EXPORT ) == 0)
1090
18.9k
    {
1091
18.9k
        OUString aValue;
1092
18.9k
        OUString sName = rNamespaceMap.GetQNameByKey(
1093
18.9k
            mpImpl->mxPropMapper->GetEntryNameSpace(rProperty.mnIndex),
1094
18.9k
            mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex));
1095
1096
18.9k
        bool bRemove = false;
1097
18.9k
        if ((mpImpl->mxPropMapper->GetEntryFlags( rProperty.mnIndex ) & MID_FLAG_MERGE_ATTRIBUTE) != 0)
1098
253
        {
1099
253
            aValue = rAttrList.getValueByName( sName );
1100
253
            bRemove = true;
1101
253
        }
1102
1103
18.9k
        if (mpImpl->mxPropMapper->exportXML(aValue, rProperty, rUnitConverter))
1104
15.7k
        {
1105
15.7k
            if( bRemove )
1106
253
                rAttrList.RemoveAttribute( sName );
1107
1108
            // We don't seem to have a generic mechanism to write an attribute in the extension
1109
            // namespace in case of certain attribute values only, so do this manually.
1110
15.7k
            sal_Int8 nExtendedStatus
1111
15.7k
                = CheckExtendedNamespace(mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex),
1112
15.7k
                                         aValue, rUnitConverter.getSaneDefaultVersion());
1113
15.7k
            if (nExtendedStatus == -1)
1114
350
                return;
1115
15.4k
            if (nExtendedStatus == 1)
1116
0
                sName = rNamespaceMap.GetQNameByKey(
1117
0
                    XML_NAMESPACE_LO_EXT, mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex));
1118
15.4k
            rAttrList.AddAttribute( sName, aValue );
1119
15.4k
        }
1120
18.9k
    }
1121
19.0k
}
1122
1123
void SvXMLExportPropertyMapper::exportElementItems(
1124
        SvXMLExport& rExport,
1125
        const ::std::vector< XMLPropertyState >& rProperties,
1126
        SvXmlExportFlags nFlags,
1127
        const std::vector<sal_uInt16>& rIndexArray ) const
1128
3.06k
{
1129
3.06k
    bool bItemsExported = false;
1130
3.06k
    for (const sal_uInt16 nElement : rIndexArray)
1131
953
    {
1132
953
        OSL_ENSURE( 0 != (mpImpl->mxPropMapper->GetEntryFlags(
1133
953
                rProperties[nElement].mnIndex ) & MID_FLAG_ELEMENT_ITEM_EXPORT),
1134
953
                "wrong mid flag!" );
1135
1136
953
        rExport.IgnorableWhitespace();
1137
953
        handleElementItem( rExport, rProperties[nElement],
1138
953
                           nFlags, &rProperties, nElement );
1139
953
        bItemsExported = true;
1140
953
    }
1141
1142
3.06k
    if( bItemsExported )
1143
855
        rExport.IgnorableWhitespace();
1144
3.06k
}
1145
1146
const rtl::Reference<XMLPropertySetMapper>& SvXMLExportPropertyMapper::getPropertySetMapper() const
1147
228k
{
1148
228k
    return mpImpl->mxPropMapper;
1149
228k
}
1150
1151
void SvXMLExportPropertyMapper::SetStyleName( const OUString& rStyleName )
1152
2.64k
{
1153
2.64k
    mpImpl->maStyleName = rStyleName;
1154
2.64k
}
1155
1156
const OUString& SvXMLExportPropertyMapper::GetStyleName() const
1157
49
{
1158
49
    return mpImpl->maStyleName;
1159
49
}
1160
1161
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */