Coverage Report

Created: 2026-11-06 11:29

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