Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/xmloff/source/transform/TransformerBase.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 <rtl/ref.hxx>
21
#include <rtl/ustrbuf.hxx>
22
#include <tools/UnitConversion.hxx>
23
#include <osl/diagnose.h>
24
#include <o3tl/numeric.hxx>
25
#include <com/sun/star/i18n/CharacterClassification.hpp>
26
#include <com/sun/star/i18n/UnicodeType.hpp>
27
#include <com/sun/star/util/MeasureUnit.hpp>
28
#include <sax/tools/converter.hxx>
29
#include <comphelper/processfactory.hxx>
30
#include <xmloff/namespacemap.hxx>
31
#include <xmloff/xmlnamespace.hxx>
32
#include "IgnoreTContext.hxx"
33
#include "RenameElemTContext.hxx"
34
#include "ProcAttrTContext.hxx"
35
#include "ProcAddAttrTContext.hxx"
36
#include "MergeElemTContext.hxx"
37
#include "CreateElemTContext.hxx"
38
#include "MutableAttrList.hxx"
39
#include "TransformerActions.hxx"
40
#include "ElemTransformerAction.hxx"
41
#include "PropertyActionsOOo.hxx"
42
#include "TransformerTokenMap.hxx"
43
44
#include "TransformerBase.hxx"
45
#include <xmloff/xmlimp.hxx>
46
47
using namespace ::xmloff::token;
48
using namespace ::com::sun::star;
49
using namespace ::com::sun::star::uno;
50
using namespace ::com::sun::star::beans;
51
using namespace ::com::sun::star::lang;
52
using namespace ::com::sun::star::i18n;
53
using namespace ::com::sun::star::xml::sax;
54
55
namespace
56
{
57
bool lcl_ConvertAttr( OUString & rOutAttribute, sal_Int32 nParam )
58
0
{
59
0
    bool bResult = false;
60
0
    enum XMLTokenEnum eTokenToRename =
61
0
        static_cast< enum XMLTokenEnum >( nParam & 0xffff );
62
0
    if( eTokenToRename != XML_TOKEN_INVALID &&
63
0
        IsXMLToken( rOutAttribute, eTokenToRename ))
64
0
    {
65
0
        enum XMLTokenEnum eReplacementToken =
66
0
            static_cast< enum XMLTokenEnum >( nParam >> 16 );
67
0
        rOutAttribute = GetXMLToken( eReplacementToken );
68
0
        bResult = true;
69
0
    }
70
0
    return bResult;
71
0
}
72
} // anonymous namespace
73
74
XMLTransformerContext *XMLTransformerBase::CreateContext( sal_uInt16 nPrefix,
75
    const OUString& rLocalName, const OUString& rQName )
76
0
{
77
0
    XMLTransformerActions::key_type aKey( nPrefix, rLocalName );
78
0
    XMLTransformerActions::const_iterator aIter =
79
0
        GetElemActions().find( aKey );
80
81
0
    if( aIter != GetElemActions().end() )
82
0
    {
83
0
        sal_uInt32 nActionType = (*aIter).second.m_nActionType;
84
0
        if( (nActionType & XML_ETACTION_USER_DEFINED) != 0 )
85
0
        {
86
0
            XMLTransformerContext *pContext =
87
0
                CreateUserDefinedContext( (*aIter).second,
88
0
                                    rQName );
89
0
            OSL_ENSURE( pContext && !pContext->IsPersistent(),
90
0
                        "unknown or not persistent action" );
91
0
            return pContext;
92
0
        }
93
94
0
        switch( nActionType )
95
0
        {
96
0
        case XML_ETACTION_COPY_CONTENT:
97
0
            return new XMLIgnoreTransformerContext( *this, rQName, false,
98
0
                                                false );
99
0
        case XML_ETACTION_COPY:
100
0
            return new XMLTransformerContext( *this, rQName );
101
0
        case XML_ETACTION_RENAME_ELEM:
102
0
            return new XMLRenameElemTransformerContext( *this, rQName,
103
0
                    (*aIter).second.GetQNamePrefixFromParam1(),
104
0
                    (*aIter).second.GetQNameTokenFromParam1() );
105
0
        case XML_ETACTION_RENAME_ELEM_ADD_ATTR:
106
0
            return new XMLRenameElemTransformerContext( *this, rQName,
107
0
                    (*aIter).second.GetQNamePrefixFromParam1(),
108
0
                    (*aIter).second.GetQNameTokenFromParam1(),
109
0
                    (*aIter).second.GetQNamePrefixFromParam2(),
110
0
                    (*aIter).second.GetQNameTokenFromParam2(),
111
0
                       static_cast< XMLTokenEnum >( (*aIter).second.m_nParam3 ) );
112
0
        case XML_ETACTION_RENAME_ELEM_PROC_ATTRS:
113
0
            return new XMLProcAttrTransformerContext( *this, rQName,
114
0
                    (*aIter).second.GetQNamePrefixFromParam1(),
115
0
                    (*aIter).second.GetQNameTokenFromParam1(),
116
0
                       static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) );
117
0
        case XML_ETACTION_RENAME_ELEM_ADD_PROC_ATTR:
118
0
            return new XMLProcAddAttrTransformerContext( *this, rQName,
119
0
                    (*aIter).second.GetQNamePrefixFromParam1(),
120
0
                    (*aIter).second.GetQNameTokenFromParam1(),
121
0
                       static_cast< sal_uInt16 >(
122
0
                        (*aIter).second.m_nParam3  >> 16 ),
123
0
                    (*aIter).second.GetQNamePrefixFromParam2(),
124
0
                    (*aIter).second.GetQNameTokenFromParam2(),
125
0
                       static_cast< XMLTokenEnum >(
126
0
                        (*aIter).second.m_nParam3 & 0xffff ) );
127
0
        case XML_ETACTION_RENAME_ELEM_PROC_ATTRS_COND:
128
0
            {
129
0
                const XMLTransformerContext *pCurrent = GetCurrentContext();
130
0
                if( pCurrent->HasQName(
131
0
                            (*aIter).second.GetQNamePrefixFromParam3(),
132
0
                            (*aIter).second.GetQNameTokenFromParam3() ) )
133
0
                    return new XMLProcAttrTransformerContext( *this, rQName,
134
0
                            (*aIter).second.GetQNamePrefixFromParam1(),
135
0
                            (*aIter).second.GetQNameTokenFromParam1(),
136
0
                            static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) );
137
0
                else
138
0
                    return new XMLProcAttrTransformerContext( *this, rQName,
139
0
                            static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) );
140
0
            }
141
0
        case XML_ETACTION_PROC_ATTRS:
142
0
            return new XMLProcAttrTransformerContext( *this, rQName,
143
0
                       static_cast< sal_uInt16 >( (*aIter).second.m_nParam1 ) );
144
0
        case XML_ETACTION_PROC_ATTRS_COND:
145
0
            {
146
0
                const XMLTransformerContext *pCurrent = GetCurrentContext();
147
0
                if( pCurrent->HasQName(
148
0
                            (*aIter).second.GetQNamePrefixFromParam1(),
149
0
                            (*aIter).second.GetQNameTokenFromParam1() ) )
150
0
                    return new XMLProcAttrTransformerContext( *this, rQName,
151
0
                            static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) );
152
0
            }
153
0
            break;
154
0
        case XML_ETACTION_MOVE_ATTRS_TO_ELEMS:
155
0
            return new XMLCreateElemTransformerContext( *this, rQName,
156
0
                       static_cast< sal_uInt16 >( (*aIter).second.m_nParam1 ) );
157
0
        case XML_ETACTION_MOVE_ELEMS_TO_ATTRS:
158
0
            return new XMLMergeElemTransformerContext( *this, rQName,
159
0
                       static_cast< sal_uInt16 >( (*aIter).second.m_nParam1 ) );
160
0
        default:
161
0
            OSL_ENSURE( false, "unknown action" );
162
0
            break;
163
0
        }
164
0
    }
165
166
    // default is copying
167
0
    return new XMLTransformerContext( *this, rQName );
168
0
}
169
170
XMLTransformerActions *XMLTransformerBase::GetUserDefinedActions( sal_uInt16 )
171
0
{
172
0
    return nullptr;
173
0
}
174
175
XMLTransformerBase::XMLTransformerBase( XMLTransformerActionInit const *pInit,
176
                                    ::xmloff::token::XMLTokenEnum const *pTKMapInit )
177
    noexcept :
178
0
    m_pNamespaceMap( new SvXMLNamespaceMap ),
179
0
    m_ElemActions( pInit ),
180
0
    m_TokenMap( pTKMapInit )
181
0
{
182
0
    GetNamespaceMap().Add( GetXMLToken(XML_NP_XLINK), GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK );
183
0
    GetNamespaceMap().Add( GetXMLToken(XML_NP_DC), GetXMLToken(XML_N_DC), XML_NAMESPACE_DC );
184
0
    GetNamespaceMap().Add( GetXMLToken(XML_NP_MATH), GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH );
185
0
    GetNamespaceMap().Add( GetXMLToken(XML_NP_OOO), GetXMLToken(XML_N_OOO), XML_NAMESPACE_OOO );
186
0
    GetNamespaceMap().Add( GetXMLToken(XML_NP_DOM), GetXMLToken(XML_N_DOM), XML_NAMESPACE_DOM );
187
0
    GetNamespaceMap().Add( GetXMLToken(XML_NP_OOOW), GetXMLToken(XML_N_OOOW), XML_NAMESPACE_OOOW );
188
0
    GetNamespaceMap().Add( GetXMLToken(XML_NP_OOOC), GetXMLToken(XML_N_OOOC), XML_NAMESPACE_OOOC );
189
0
}
190
191
XMLTransformerBase::~XMLTransformerBase() noexcept
192
0
{
193
0
}
194
195
void SAL_CALL XMLTransformerBase::startDocument()
196
0
{
197
0
    m_xHandler->startDocument();
198
0
}
199
200
void SAL_CALL XMLTransformerBase::endDocument()
201
0
{
202
0
    m_xHandler->endDocument();
203
0
}
204
205
void SAL_CALL XMLTransformerBase::startElement( const OUString& rName,
206
                                         const Reference< XAttributeList >& rAttrList )
207
0
{
208
0
    std::unique_ptr<SvXMLNamespaceMap> pRewindMap;
209
210
    // Process namespace attributes. This must happen before creating the
211
    // context, because namespace declaration apply to the element name itself.
212
0
    rtl::Reference<XMLMutableAttributeList> pMutableAttrList;
213
0
    Reference< XAttributeList > xAttrList( rAttrList );
214
0
    sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
215
0
    for( sal_Int16 i=0; i < nAttrCount; i++ )
216
0
    {
217
0
        const OUString aAttrName = xAttrList->getNameByIndex( i );
218
0
        if( ( aAttrName.getLength() >= 5 ) &&
219
0
            ( aAttrName.startsWith( GetXMLToken(XML_XMLNS) ) ) &&
220
0
            ( aAttrName.getLength() == 5 || ':' == aAttrName[5] ) )
221
0
        {
222
0
            if( !pRewindMap )
223
0
            {
224
0
                pRewindMap = std::move(m_pNamespaceMap);
225
0
                m_pNamespaceMap.reset( new SvXMLNamespaceMap( *pRewindMap ) );
226
0
            }
227
0
            const OUString aAttrValue = xAttrList->getValueByIndex( i );
228
229
0
            OUString aPrefix( ( aAttrName.getLength() == 5 )
230
0
                                 ? OUString()
231
0
                                 : aAttrName.copy( 6 ) );
232
            // Add namespace, but only if it is known.
233
0
            sal_uInt16 nKey = m_pNamespaceMap->AddIfKnown( aPrefix, aAttrValue );
234
            // If namespace is unknown, try to match a name with similar
235
            // TC Id and version
236
0
            if( XML_NAMESPACE_UNKNOWN == nKey  )
237
0
            {
238
0
                OUString aTestName( aAttrValue );
239
0
                if( SvXMLNamespaceMap::NormalizeOasisURN( aTestName ) )
240
0
                    nKey = m_pNamespaceMap->AddIfKnown( aPrefix, aTestName );
241
0
            }
242
            // If that namespace is not known, too, add it as unknown
243
0
            if( XML_NAMESPACE_UNKNOWN == nKey  )
244
0
                nKey = m_pNamespaceMap->Add( aPrefix, aAttrValue );
245
246
0
            const OUString& rRepName = m_vReplaceNamespaceMap.GetNameByKey( nKey );
247
0
            if( !rRepName.isEmpty() )
248
0
            {
249
0
                if( !pMutableAttrList )
250
0
                {
251
0
                    pMutableAttrList = new XMLMutableAttributeList( xAttrList );
252
0
                    xAttrList = pMutableAttrList;
253
0
                }
254
255
0
                pMutableAttrList->SetValueByIndex( i, rRepName );
256
0
            }
257
0
        }
258
0
    }
259
260
    // Get element's namespace and local name.
261
0
    OUString aLocalName;
262
0
    sal_uInt16 nPrefix =
263
0
        m_pNamespaceMap->GetKeyByAttrName( rName, &aLocalName );
264
265
    // If there are contexts already, call a CreateChildContext at the topmost
266
    // context. Otherwise, create a default context.
267
0
    ::rtl::Reference < XMLTransformerContext > xContext;
268
0
    if( !m_vContexts.empty() )
269
0
    {
270
0
        xContext = m_vContexts.back()->CreateChildContext( nPrefix,
271
0
                                                          aLocalName,
272
0
                                                          rName,
273
0
                                                          xAttrList );
274
0
    }
275
0
    else
276
0
    {
277
0
        xContext = CreateContext( nPrefix, aLocalName, rName );
278
0
    }
279
280
0
    OSL_ENSURE( xContext.is(), "XMLTransformerBase::startElement: missing context" );
281
0
    if( !xContext.is() )
282
0
        xContext = new XMLTransformerContext( *this, rName );
283
284
    // Remember old namespace map.
285
0
    if( pRewindMap )
286
0
        xContext->PutRewindMap( std::move(pRewindMap) );
287
288
    // Push context on stack.
289
0
    m_vContexts.push_back( xContext );
290
291
    // Call a startElement at the new context.
292
0
    xContext->StartElement( xAttrList );
293
0
}
294
295
void SAL_CALL XMLTransformerBase::endElement( const OUString&
296
#if OSL_DEBUG_LEVEL > 0
297
rName
298
#endif
299
)
300
0
{
301
0
    if( m_vContexts.empty() )
302
0
        return;
303
304
    // Get topmost context
305
0
    ::rtl::Reference< XMLTransformerContext > xContext = m_vContexts.back();
306
307
#if OSL_DEBUG_LEVEL > 0
308
    OSL_ENSURE( xContext->GetQName() == rName,
309
            "XMLTransformerBase::endElement: popped context has wrong lname" );
310
#endif
311
312
    // Call a EndElement at the current context.
313
0
    xContext->EndElement();
314
315
    // and remove it from the stack.
316
0
    m_vContexts.pop_back();
317
318
    // Get a namespace map to rewind.
319
0
    std::unique_ptr<SvXMLNamespaceMap> pRewindMap = xContext->TakeRewindMap();
320
321
    // Delete the current context.
322
0
    xContext = nullptr;
323
324
    // Rewind a namespace map.
325
0
    if( pRewindMap )
326
0
    {
327
0
        m_pNamespaceMap = std::move( pRewindMap );
328
0
    }
329
0
}
330
331
void SAL_CALL XMLTransformerBase::characters( const OUString& rChars )
332
0
{
333
0
    if( !m_vContexts.empty() )
334
0
    {
335
0
        m_vContexts.back()->Characters( rChars );
336
0
    }
337
0
}
338
339
void SAL_CALL XMLTransformerBase::ignorableWhitespace( const OUString& rWhitespaces )
340
0
{
341
0
    m_xHandler->ignorableWhitespace( rWhitespaces );
342
0
}
343
344
void SAL_CALL XMLTransformerBase::processingInstruction( const OUString& rTarget,
345
                                       const OUString& rData )
346
0
{
347
0
    m_xHandler->processingInstruction( rTarget, rData );
348
0
}
349
350
void SAL_CALL XMLTransformerBase::setDocumentLocator( const Reference< XLocator >& )
351
0
{
352
0
}
353
354
// XExtendedDocumentHandler
355
void SAL_CALL XMLTransformerBase::startCDATA()
356
0
{
357
0
}
358
359
void SAL_CALL XMLTransformerBase::endCDATA()
360
0
{
361
0
}
362
363
void SAL_CALL XMLTransformerBase::comment( const OUString& /*rComment*/ )
364
0
{
365
0
}
366
367
void SAL_CALL XMLTransformerBase::allowLineBreak()
368
0
{
369
0
}
370
371
void SAL_CALL XMLTransformerBase::unknown( const OUString& /*rString*/ )
372
0
{
373
0
}
374
375
// XInitialize
376
void SAL_CALL XMLTransformerBase::initialize( const Sequence< Any >& aArguments )
377
0
{
378
0
    for( const auto& rArgument : aArguments )
379
0
    {
380
        // use isAssignableFrom instead of comparing the types to
381
        // allow XExtendedDocumentHandler instead of XDocumentHandler (used in
382
        // writeOasis2OOoLibraryElement in sfx2).
383
        // The Any shift operator can't be used to query the type because it
384
        // uses queryInterface, and the model also has a XPropertySet interface.
385
386
0
        css::uno::Reference< XFastDocumentHandler > xFastHandler;
387
0
        if( (rArgument >>= xFastHandler) && xFastHandler )
388
0
        {
389
0
            SvXMLImport *pFastHandler = static_cast<SvXMLImport*>( xFastHandler.get() );
390
0
            m_xHandler.set( new SvXMLLegacyToFastDocHandler( pFastHandler ) );
391
0
        }
392
        // document handler
393
0
        else if( cppu::UnoType<XDocumentHandler>::get().isAssignableFrom( rArgument.getValueType() ) )
394
0
        {
395
0
            m_xHandler.set( rArgument, UNO_QUERY );
396
0
        }
397
        // property set to transport data across
398
0
        else if( cppu::UnoType<XPropertySet>::get().isAssignableFrom( rArgument.getValueType() ) )
399
0
            m_xPropSet.set( rArgument, UNO_QUERY );
400
        // xmodel
401
0
        else if( cppu::UnoType<css::frame::XModel>::get().isAssignableFrom( rArgument.getValueType() ) )
402
0
            mxModel.set( rArgument, UNO_QUERY );
403
0
    }
404
405
0
    if( m_xPropSet.is() )
406
0
    {
407
0
        Any aAny;
408
0
        OUString sRelPath, sName;
409
0
        Reference< XPropertySetInfo > xPropSetInfo =
410
0
            m_xPropSet->getPropertySetInfo();
411
0
        OUString sPropName( u"StreamRelPath"_ustr  );
412
0
        if( xPropSetInfo->hasPropertyByName(sPropName) )
413
0
        {
414
0
            aAny = m_xPropSet->getPropertyValue(sPropName);
415
0
            aAny >>= sRelPath;
416
0
        }
417
0
        sPropName = "StreamName";
418
0
        if( xPropSetInfo->hasPropertyByName(sPropName) )
419
0
        {
420
0
            aAny = m_xPropSet->getPropertyValue(sPropName);
421
0
            aAny >>= sName;
422
0
        }
423
0
        if( !sName.isEmpty() )
424
0
        {
425
0
            m_aExtPathPrefix = "../";
426
427
            // If there is a rel path within a package, then append
428
            // additional '../'. If the rel path contains an ':', then it is
429
            // an absolute URI (or invalid URI, because zip files don't
430
            // permit ':'), and it will be ignored.
431
0
            if( !sRelPath.isEmpty() )
432
0
            {
433
0
                sal_Int32 nColPos = sRelPath.indexOf( ':' );
434
0
                OSL_ENSURE( -1 == nColPos,
435
0
                            "StreamRelPath contains ':', absolute URI?" );
436
437
0
                if( -1 == nColPos )
438
0
                {
439
0
                    OUString sTmp = m_aExtPathPrefix;
440
0
                    sal_Int32 nPos = 0;
441
0
                    do
442
0
                    {
443
0
                        m_aExtPathPrefix += sTmp;
444
0
                        nPos = sRelPath.indexOf( '/', nPos + 1 );
445
0
                    }
446
0
                    while( -1 != nPos );
447
0
                }
448
0
            }
449
450
0
        }
451
0
    }
452
453
0
    assert(m_xHandler.is()); // can't do anything without that
454
0
}
455
456
static sal_Int16 lcl_getUnit( std::u16string_view rValue )
457
0
{
458
0
    if( o3tl::endsWithIgnoreAsciiCase( rValue, "cm" ) )
459
0
        return util::MeasureUnit::CM;
460
0
    else if ( o3tl::endsWithIgnoreAsciiCase( rValue, "mm" ) )
461
0
        return util::MeasureUnit::MM;
462
0
    else
463
0
        return util::MeasureUnit::INCH;
464
0
}
465
466
XMLMutableAttributeList *XMLTransformerBase::ProcessAttrList(
467
        Reference< XAttributeList >& rAttrList, sal_uInt16 nActionMap,
468
           bool bClone  )
469
0
{
470
0
    rtl::Reference<XMLMutableAttributeList> pMutableAttrList;
471
0
    XMLTransformerActions *pActions = GetUserDefinedActions( nActionMap );
472
0
    OSL_ENSURE( pActions, "go no actions" );
473
0
    if( pActions )
474
0
    {
475
0
        sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0;
476
0
        for( sal_Int16 i=0; i < nAttrCount; ++i )
477
0
        {
478
0
            const OUString aAttrName = rAttrList->getNameByIndex( i );
479
0
            const OUString aAttrValue = rAttrList->getValueByIndex( i );
480
0
            OUString aLocalName;
481
0
            sal_uInt16 nPrefix = GetNamespaceMap().GetKeyByAttrName( aAttrName,
482
0
                                                           &aLocalName );
483
484
0
            XMLTransformerActions::key_type aKey( nPrefix, aLocalName );
485
0
            XMLTransformerActions::const_iterator aIter =
486
0
                    pActions->find( aKey );
487
0
            if( aIter != pActions->end() )
488
0
            {
489
0
                if( !pMutableAttrList )
490
0
                {
491
0
                    pMutableAttrList = new XMLMutableAttributeList( rAttrList,
492
0
                                                                    bClone );
493
0
                    rAttrList = pMutableAttrList;
494
0
                }
495
496
0
                sal_uInt32 nAction = (*aIter).second.m_nActionType;
497
0
                bool bRename = false;
498
0
                switch( nAction )
499
0
                {
500
0
                case XML_ATACTION_RENAME:
501
0
                    bRename = true;
502
0
                    break;
503
0
                case XML_ATACTION_COPY:
504
0
                    break;
505
0
                case XML_ATACTION_REMOVE:
506
0
                case XML_ATACTION_STYLE_DISPLAY_NAME:
507
0
                    pMutableAttrList->RemoveAttributeByIndex( i );
508
0
                    --i;
509
0
                    --nAttrCount;
510
0
                    break;
511
0
                case XML_ATACTION_RENAME_IN2INCH:
512
0
                    bRename = true;
513
0
                    [[fallthrough]];
514
0
                case XML_ATACTION_IN2INCH:
515
0
                    {
516
0
                        OUString aAttrValue2( aAttrValue );
517
0
                        if( ReplaceSingleInWithInch( aAttrValue2 ) )
518
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
519
0
                    }
520
0
                    break;
521
0
                case XML_ATACTION_INS2INCHS:
522
0
                    {
523
0
                        OUString aAttrValue2( aAttrValue );
524
0
                        if( ReplaceInWithInch( aAttrValue2 ) )
525
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
526
0
                    }
527
0
                    break;
528
0
                case XML_ATACTION_RENAME_INCH2IN:
529
0
                    bRename = true;
530
0
                    [[fallthrough]];
531
0
                case XML_ATACTION_INCH2IN:
532
0
                    {
533
0
                        OUString aAttrValue2( aAttrValue );
534
0
                        if( ReplaceSingleInchWithIn( aAttrValue2 ) )
535
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
536
0
                    }
537
0
                    break;
538
0
                case XML_ATACTION_INCHS2INS:
539
0
                    {
540
0
                        OUString aAttrValue2( aAttrValue );
541
0
                        if( ReplaceInchWithIn( aAttrValue2 ) )
542
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
543
0
                    }
544
0
                    break;
545
0
                case XML_ATACTION_TWIPS2IN:
546
0
                    {
547
0
                        OUString aAttrValue2( aAttrValue );
548
549
0
                        XMLTransformerBase::ReplaceSingleInchWithIn( aAttrValue2 );
550
0
                        if( isWriter() )
551
0
                        {
552
0
                            sal_Int16 const nDestUnit = lcl_getUnit(aAttrValue2);
553
554
                            // convert twips value to inch
555
0
                            sal_Int32 nMeasure;
556
0
                            if (::sax::Converter::convertMeasure(nMeasure,
557
0
                                    aAttrValue2))
558
0
                            {
559
0
                                nMeasure = static_cast<sal_Int32>(convertTwipToMm100(nMeasure));
560
561
0
                                OUStringBuffer aBuffer;
562
0
                                ::sax::Converter::convertMeasure(aBuffer,
563
0
                                        nMeasure, util::MeasureUnit::MM_100TH,
564
0
                                        nDestUnit );
565
0
                                aAttrValue2 = aBuffer.makeStringAndClear();
566
0
                            }
567
0
                        }
568
569
0
                        pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
570
0
                    }
571
0
                    break;
572
0
                case XML_ATACTION_RENAME_DECODE_STYLE_NAME_REF:
573
0
                    bRename = true;
574
0
                    [[fallthrough]];
575
0
                case XML_ATACTION_DECODE_STYLE_NAME:
576
0
                case XML_ATACTION_DECODE_STYLE_NAME_REF:
577
0
                    {
578
0
                        OUString aAttrValue2( aAttrValue );
579
0
                        if( DecodeStyleName(aAttrValue2) )
580
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
581
0
                    }
582
0
                    break;
583
0
                case XML_ATACTION_ENCODE_STYLE_NAME:
584
0
                    {
585
0
                        OUString aAttrValue2( aAttrValue );
586
0
                        if( EncodeStyleName(aAttrValue2) )
587
0
                        {
588
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
589
0
                            OUString aNewAttrQName(
590
0
                                GetNamespaceMap().GetQNameByKey(
591
0
                                    nPrefix,
592
0
                                ::xmloff::token::GetXMLToken(
593
0
                                XML_DISPLAY_NAME ) ) );
594
0
                            pMutableAttrList->AddAttribute( aNewAttrQName,
595
0
                                                            aAttrValue );
596
0
                        }
597
0
                    }
598
0
                    break;
599
0
                case XML_ATACTION_RENAME_ENCODE_STYLE_NAME_REF:
600
0
                    bRename = true;
601
0
                    [[fallthrough]];
602
0
                case XML_ATACTION_ENCODE_STYLE_NAME_REF:
603
0
                    {
604
0
                        OUString aAttrValue2( aAttrValue );
605
0
                        if( EncodeStyleName(aAttrValue2) )
606
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
607
0
                    }
608
0
                    break;
609
0
                case XML_ATACTION_RENAME_NEG_PERCENT:
610
0
                    bRename = true;
611
0
                    [[fallthrough]];
612
0
                case XML_ATACTION_NEG_PERCENT:
613
0
                    {
614
0
                        OUString aAttrValue2( aAttrValue );
615
0
                        if( NegPercent( aAttrValue2 ) )
616
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
617
0
                    }
618
0
                    break;
619
0
                case XML_ATACTION_RENAME_ADD_NAMESPACE_PREFIX:
620
0
                    bRename = true;
621
0
                    [[fallthrough]];
622
0
                case XML_ATACTION_ADD_NAMESPACE_PREFIX:
623
0
                    {
624
0
                        OUString aAttrValue2( aAttrValue );
625
0
                        sal_uInt16 nValPrefix =
626
0
                            static_cast<sal_uInt16>(
627
0
                                    bRename ? (*aIter).second.m_nParam2
628
0
                                            : (*aIter).second.m_nParam1);
629
0
                        AddNamespacePrefix( aAttrValue2, nValPrefix );
630
0
                        pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
631
0
                    }
632
0
                    break;
633
0
                case XML_ATACTION_ADD_APP_NAMESPACE_PREFIX:
634
0
                    {
635
0
                        OUString aAttrValue2( aAttrValue );
636
0
                        sal_uInt16 nValPrefix =
637
0
                            static_cast<sal_uInt16>((*aIter).second.m_nParam1);
638
0
                        if( IsXMLToken( GetClass(), XML_SPREADSHEET  ) )
639
0
                            nValPrefix = XML_NAMESPACE_OOOC;
640
0
                        else if( IsXMLToken( GetClass(), XML_TEXT  ) )
641
0
                            nValPrefix = XML_NAMESPACE_OOOW;
642
0
                        AddNamespacePrefix( aAttrValue2, nValPrefix );
643
0
                        pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
644
0
                    }
645
0
                    break;
646
0
                case XML_ATACTION_RENAME_REMOVE_NAMESPACE_PREFIX:
647
0
                    bRename = true;
648
0
                    [[fallthrough]];
649
0
                case XML_ATACTION_REMOVE_NAMESPACE_PREFIX:
650
0
                    {
651
0
                        OUString aAttrValue2( aAttrValue );
652
0
                        sal_uInt16 nValPrefix =
653
0
                            static_cast<sal_uInt16>(
654
0
                                    bRename ? (*aIter).second.m_nParam2
655
0
                                            : (*aIter).second.m_nParam1);
656
0
                        if( RemoveNamespacePrefix( aAttrValue2, nValPrefix ) )
657
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
658
0
                    }
659
0
                    break;
660
0
                case XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX:
661
0
                    {
662
0
                        OUString aAttrValue2( aAttrValue );
663
0
                        if( RemoveNamespacePrefix( aAttrValue2 ) )
664
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
665
0
                    }
666
0
                    break;
667
0
                case XML_ATACTION_URI_OOO:
668
0
                    {
669
0
                        OUString aAttrValue2( aAttrValue );
670
0
                        if( ConvertURIToOASIS( aAttrValue2,
671
0
                            static_cast< bool >((*aIter).second.m_nParam1)))
672
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
673
0
                    }
674
0
                    break;
675
0
                case XML_ATACTION_URI_OASIS:
676
0
                    {
677
0
                        OUString aAttrValue2( aAttrValue );
678
0
                        if( ConvertURIToOOo( aAttrValue2,
679
0
                            static_cast< bool >((*aIter).second.m_nParam1)))
680
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
681
0
                    }
682
0
                    break;
683
0
                case XML_ATACTION_RENAME_ATTRIBUTE:
684
0
                    {
685
0
                        OUString aAttrValue2( aAttrValue );
686
0
                        RenameAttributeValue(
687
0
                            aAttrValue2,
688
0
                            (*aIter).second.m_nParam1,
689
0
                            (*aIter).second.m_nParam2,
690
0
                            (*aIter).second.m_nParam3 );
691
0
                        pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
692
0
                    }
693
0
                    break;
694
0
                case XML_ATACTION_RNG2ISO_DATETIME:
695
0
                    {
696
0
                        OUString aAttrValue2( aAttrValue );
697
0
                        if( ConvertRNGDateTimeToISO( aAttrValue2 ))
698
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
699
0
                    }
700
0
                    break;
701
0
                case XML_ATACTION_RENAME_RNG2ISO_DATETIME:
702
0
                    {
703
0
                        OUString aAttrValue2( aAttrValue );
704
0
                        if( ConvertRNGDateTimeToISO( aAttrValue2 ))
705
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
706
0
                        bRename = true;
707
0
                    }
708
0
                    break;
709
0
                case XML_ATACTION_IN2TWIPS:
710
0
                    {
711
0
                        OUString aAttrValue2( aAttrValue );
712
0
                        XMLTransformerBase::ReplaceSingleInWithInch( aAttrValue2 );
713
714
0
                        if( isWriter() )
715
0
                        {
716
0
                            sal_Int16 const nDestUnit = lcl_getUnit(aAttrValue2);
717
718
                            // convert inch value to twips and export as faked inch
719
0
                            sal_Int32 nMeasure;
720
0
                            if (::sax::Converter::convertMeasure(nMeasure,
721
0
                                    aAttrValue2))
722
0
                            {
723
0
                                nMeasure = o3tl::toTwips(nMeasure, o3tl::Length::mm100);
724
725
0
                                OUStringBuffer aBuffer;
726
0
                                ::sax::Converter::convertMeasure( aBuffer,
727
0
                                        nMeasure, util::MeasureUnit::MM_100TH,
728
0
                                        nDestUnit );
729
0
                                aAttrValue2 = aBuffer.makeStringAndClear();
730
0
                            }
731
0
                        }
732
733
0
                        pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
734
0
                    }
735
0
                    break;
736
0
                case XML_ATACTION_SVG_WIDTH_HEIGHT_OOO:
737
0
                    {
738
0
                        OUString aAttrValue2( aAttrValue );
739
0
                        ReplaceSingleInchWithIn( aAttrValue2 );
740
741
0
                        sal_Int16 const nDestUnit = lcl_getUnit( aAttrValue2 );
742
743
0
                        sal_Int32 nMeasure;
744
0
                        if (::sax::Converter::convertMeasure(nMeasure,
745
0
                                    aAttrValue2))
746
0
                        {
747
748
0
                            if( nMeasure > 0 )
749
0
                                nMeasure -= 1;
750
0
                            else if( nMeasure < 0 )
751
0
                                nMeasure += 1;
752
753
754
0
                            OUStringBuffer aBuffer;
755
0
                            ::sax::Converter::convertMeasure(aBuffer, nMeasure,
756
0
                                   util::MeasureUnit::MM_100TH, nDestUnit);
757
0
                            aAttrValue2 = aBuffer.makeStringAndClear();
758
0
                        }
759
760
0
                        pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
761
0
                    }
762
0
                    break;
763
0
                case XML_ATACTION_SVG_WIDTH_HEIGHT_OASIS:
764
0
                    {
765
0
                        OUString aAttrValue2( aAttrValue );
766
0
                        ReplaceSingleInWithInch( aAttrValue2 );
767
768
0
                        sal_Int16 const nDestUnit = lcl_getUnit( aAttrValue2 );
769
770
0
                        sal_Int32 nMeasure;
771
0
                        if (::sax::Converter::convertMeasure(nMeasure,
772
0
                                aAttrValue2))
773
0
                        {
774
775
0
                            if( nMeasure > 0 )
776
0
                                nMeasure += 1;
777
0
                            else if( nMeasure < 0 )
778
0
                                nMeasure -= 1;
779
780
781
0
                            OUStringBuffer aBuffer;
782
0
                            ::sax::Converter::convertMeasure(aBuffer, nMeasure,
783
0
                                    util::MeasureUnit::MM_100TH, nDestUnit );
784
0
                            aAttrValue2 = aBuffer.makeStringAndClear();
785
0
                        }
786
787
0
                        pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
788
0
                    }
789
0
                    break;
790
0
                case XML_ATACTION_DECODE_ID:
791
0
                    {
792
0
                        const sal_Int32 nLen = aAttrValue.getLength();
793
0
                        OUStringBuffer aBuffer;
794
795
0
                        sal_Int32 pos;
796
0
                        for( pos = 0; pos < nLen; pos++ )
797
0
                        {
798
0
                            sal_Unicode c = aAttrValue[pos];
799
0
                            if( (c >= '0') && (c <= '9') )
800
0
                                aBuffer.append( c );
801
0
                            else
802
0
                                aBuffer.append( static_cast<sal_Int32>(c) );
803
0
                        }
804
805
0
                        pMutableAttrList->SetValueByIndex( i, aBuffer.makeStringAndClear() );
806
0
                    }
807
0
                    break;
808
                // #i50322# - special handling for the
809
                // transparency of writer background graphics.
810
0
                case XML_ATACTION_WRITER_BACK_GRAPHIC_TRANSPARENCY:
811
0
                    {
812
                        // determine, if it's the transparency of a document style
813
0
                        XMLTransformerContext* pFirstContext = m_vContexts[0].get();
814
0
                        OUString aFirstContextLocalName;
815
                        /* sal_uInt16 nFirstContextPrefix = */
816
0
                        GetNamespaceMap().GetKeyByAttrName( pFirstContext->GetQName(),
817
0
                                                                &aFirstContextLocalName );
818
0
                        bool bIsDocumentStyle(
819
0
                            ::xmloff::token::IsXMLToken( aFirstContextLocalName,
820
0
                                                         XML_DOCUMENT_STYLES ) );
821
                        // no conversion of transparency value for document
822
                        // styles, because former OpenOffice.org version writes
823
                        // writes always a transparency value of 100% and doesn't
824
                        // read the value. Thus, it's interpreted as 0%
825
0
                        if ( !bIsDocumentStyle )
826
0
                        {
827
0
                            OUString aAttrValue2( aAttrValue );
828
0
                            NegPercent(aAttrValue2);
829
0
                            pMutableAttrList->SetValueByIndex( i, aAttrValue2 );
830
0
                        }
831
0
                        bRename = true;
832
0
                    }
833
0
                    break;
834
0
                case XML_ATACTION_SHAPEID:
835
0
                {
836
0
                    OUString sNewValue = "shape" + aAttrValue;
837
0
                    pMutableAttrList->SetValueByIndex( i, sNewValue );
838
0
                    break;
839
0
                }
840
841
0
                default:
842
0
                    OSL_ENSURE( false, "unknown action" );
843
0
                    break;
844
0
                }
845
846
0
                if( bRename )
847
0
                {
848
0
                    OUString aNewAttrQName(
849
0
                        GetNamespaceMap().GetQNameByKey(
850
0
                            (*aIter).second.GetQNamePrefixFromParam1(),
851
0
                            ::xmloff::token::GetXMLToken(
852
0
                                (*aIter).second.GetQNameTokenFromParam1()) ) );
853
0
                    pMutableAttrList->RenameAttributeByIndex( i,
854
0
                                                              aNewAttrQName );
855
0
                }
856
0
            }
857
0
        }
858
0
    }
859
860
0
    return pMutableAttrList.get();
861
0
}
862
863
bool XMLTransformerBase::ReplaceSingleInchWithIn( OUString& rValue )
864
0
{
865
0
    bool bRet = false;
866
0
    sal_Int32 nPos = rValue.getLength();
867
0
    while( nPos && rValue[nPos-1] <= ' ' )
868
0
        --nPos;
869
0
    if( nPos > 2 &&
870
0
        ('c'==rValue[nPos-2] || 'C'==rValue[nPos-2]) &&
871
0
        ('h'==rValue[nPos-1] || 'H'==rValue[nPos-1]) )
872
0
    {
873
0
        rValue =rValue.copy( 0, nPos-2 );
874
0
        bRet = true;
875
0
    }
876
877
0
    return bRet;
878
0
}
879
880
bool XMLTransformerBase::ReplaceInchWithIn( OUString& rValue )
881
0
{
882
0
    bool bRet = false;
883
0
    sal_Int32 nPos = 1;
884
0
    while( nPos < rValue.getLength()-3 )
885
0
    {
886
0
        sal_Unicode c = rValue[nPos];
887
0
        if( 'i'==c || 'I'==c )
888
0
        {
889
0
            c = rValue[nPos-1];
890
0
            if( (c >= '0' && c <= '9') || '.' == c )
891
0
            {
892
0
                c = rValue[nPos+1];
893
0
                if( 'n'==c || 'N'==c )
894
0
                {
895
0
                    c = rValue[nPos+2];
896
0
                    if( 'c'==c || 'C'==c )
897
0
                    {
898
0
                        c = rValue[nPos+3];
899
0
                        if( 'h'==c || 'H'==c )
900
0
                        {
901
0
                            rValue = rValue.replaceAt( nPos,
902
0
                                4, GetXMLToken(XML_IN) );
903
0
                            nPos += 2;
904
0
                            bRet = true;
905
0
                            continue;
906
0
                        }
907
0
                    }
908
0
                }
909
0
            }
910
0
        }
911
0
        ++nPos;
912
0
    }
913
914
0
    return bRet;
915
0
}
916
917
bool XMLTransformerBase::ReplaceSingleInWithInch( OUString& rValue )
918
0
{
919
0
    bool bRet = false;
920
921
0
    sal_Int32 nPos = rValue.getLength();
922
0
    while( nPos && rValue[nPos-1] <= ' ' )
923
0
        --nPos;
924
0
    if( nPos > 2 &&
925
0
        ('i'==rValue[nPos-2] ||
926
0
            'I'==rValue[nPos-2]) &&
927
0
        ('n'==rValue[nPos-1] ||
928
0
            'N'==rValue[nPos-1]) )
929
0
    {
930
0
        nPos -= 2;
931
0
        rValue = rValue.replaceAt( nPos, rValue.getLength() - nPos,
932
0
                                           GetXMLToken(XML_INCH) );
933
0
        bRet = true;
934
0
    }
935
936
0
    return bRet;
937
0
}
938
939
bool XMLTransformerBase::ReplaceInWithInch( OUString& rValue )
940
0
{
941
0
    bool bRet = false;
942
0
    sal_Int32 nPos = 1;
943
0
    while( nPos < rValue.getLength()-1 )
944
0
    {
945
0
        sal_Unicode c = rValue[nPos];
946
0
        if( 'i'==c || 'I'==c )
947
0
        {
948
0
            c = rValue[nPos-1];
949
0
            if( (c >= '0' && c <= '9') || '.' == c )
950
0
            {
951
0
                c = rValue[nPos+1];
952
0
                if( 'n'==c || 'N'==c )
953
0
                {
954
0
                    rValue = rValue.replaceAt( nPos,
955
0
                                    2, GetXMLToken(XML_INCH) );
956
0
                    nPos += 4;
957
0
                    bRet = true;
958
0
                    continue;
959
0
                }
960
0
            }
961
0
        }
962
0
        ++nPos;
963
0
    }
964
965
0
    return bRet;
966
0
}
967
968
bool XMLTransformerBase::EncodeStyleName( OUString& rName ) const
969
0
{
970
0
    static const char aHexTab[] = "0123456789abcdef";
971
972
0
    bool bEncoded = false;
973
974
0
    sal_Int32 nLen = rName.getLength();
975
0
    OUStringBuffer aBuffer( nLen );
976
977
0
    for( sal_Int32 i = 0; i < nLen; i++ )
978
0
    {
979
0
        sal_Unicode c = rName[i];
980
0
        bool bValidChar = false;
981
0
        if( c < 0x00ffU )
982
0
        {
983
0
            bValidChar =
984
0
                (c >= 0x0041 && c <= 0x005a) ||
985
0
                (c >= 0x0061 && c <= 0x007a) ||
986
0
                (c >= 0x00c0 && c <= 0x00d6) ||
987
0
                (c >= 0x00d8 && c <= 0x00f6) ||
988
0
                (c >= 0x00f8 && c <= 0x00ff) ||
989
0
                ( i > 0 && ( (c >= 0x0030 && c <= 0x0039) ||
990
0
                             c == 0x00b7 || c == '-' || c == '.') );
991
0
        }
992
0
        else
993
0
        {
994
0
            if( (c >= 0xf900U && c <= 0xfffeU) ||
995
0
                 (c >= 0x20ddU && c <= 0x20e0U))
996
0
            {
997
0
                bValidChar = false;
998
0
            }
999
0
            else if( (c >= 0x02bbU && c <= 0x02c1U) || c == 0x0559 ||
1000
0
                     c == 0x06e5 || c == 0x06e6 )
1001
0
            {
1002
0
                bValidChar = true;
1003
0
            }
1004
0
            else if( c == 0x0387 )
1005
0
            {
1006
0
                bValidChar = i > 0;
1007
0
            }
1008
0
            else
1009
0
            {
1010
0
                if( !xCharClass.is() )
1011
0
                {
1012
0
                    const_cast < XMLTransformerBase * >(this)
1013
0
                        ->xCharClass = CharacterClassification::create( comphelper::getProcessComponentContext() );
1014
0
                }
1015
0
                sal_Int16 nType = xCharClass->getType( rName, i );
1016
1017
0
                switch( nType )
1018
0
                {
1019
0
                case UnicodeType::UPPERCASE_LETTER:     // Lu
1020
0
                case UnicodeType::LOWERCASE_LETTER:     // Ll
1021
0
                case UnicodeType::TITLECASE_LETTER:     // Lt
1022
0
                case UnicodeType::OTHER_LETTER:         // Lo
1023
0
                case UnicodeType::LETTER_NUMBER:        // Nl
1024
0
                    bValidChar = true;
1025
0
                    break;
1026
0
                case UnicodeType::NON_SPACING_MARK:     // Ms
1027
0
                case UnicodeType::ENCLOSING_MARK:       // Me
1028
0
                case UnicodeType::COMBINING_SPACING_MARK:   //Mc
1029
0
                case UnicodeType::MODIFIER_LETTER:      // Lm
1030
0
                case UnicodeType::DECIMAL_DIGIT_NUMBER: // Nd
1031
0
                    bValidChar = i > 0;
1032
0
                    break;
1033
0
                }
1034
0
            }
1035
0
        }
1036
0
        if( bValidChar )
1037
0
        {
1038
0
            aBuffer.append( c );
1039
0
        }
1040
0
        else
1041
0
        {
1042
0
            aBuffer.append( '_' );
1043
0
            if( c > 0x0fff )
1044
0
                aBuffer.append( static_cast< sal_Unicode >(
1045
0
                            aHexTab[ (c >> 12) & 0x0f ]  ) );
1046
0
            if( c > 0x00ff )
1047
0
                aBuffer.append( static_cast< sal_Unicode >(
1048
0
                        aHexTab[ (c >> 8) & 0x0f ] ) );
1049
0
            if( c > 0x000f )
1050
0
                aBuffer.append( static_cast< sal_Unicode >(
1051
0
                        aHexTab[ (c >> 4) & 0x0f ] ) );
1052
0
            aBuffer.append(
1053
0
                OUString::number(static_cast< sal_Unicode >( aHexTab[ c & 0x0f ] ) )
1054
0
                + "_" );
1055
0
            bEncoded = true;
1056
0
        }
1057
0
    }
1058
1059
0
    if( aBuffer.getLength() > (1<<15)-1 )
1060
0
        bEncoded = false;
1061
1062
0
    if( bEncoded )
1063
0
        rName = aBuffer.makeStringAndClear();
1064
0
    return bEncoded;
1065
0
}
1066
1067
bool XMLTransformerBase::DecodeStyleName( OUString& rName )
1068
0
{
1069
0
    bool bEncoded = false;
1070
1071
0
    sal_Int32 nLen = rName.getLength();
1072
0
    OUStringBuffer aBuffer( nLen );
1073
1074
0
    bool bWithinHex = false;
1075
0
    sal_Unicode cEnc = 0;
1076
0
    for( sal_Int32 i = 0; i < nLen; i++ )
1077
0
    {
1078
0
        sal_Unicode c = rName[i];
1079
0
        if( '_' == c )
1080
0
        {
1081
0
            if( bWithinHex )
1082
0
            {
1083
0
                aBuffer.append( cEnc );
1084
0
                cEnc = 0;
1085
0
            }
1086
0
            else
1087
0
            {
1088
0
                bEncoded = true;
1089
0
            }
1090
0
            bWithinHex = !bWithinHex;
1091
0
        }
1092
0
        else if( bWithinHex )
1093
0
        {
1094
0
            int nValue = o3tl::convertToHex<int>(c);
1095
0
            if (nValue == -1)
1096
0
            {
1097
                // error
1098
0
                bEncoded = false;
1099
0
                break;
1100
0
            }
1101
0
            cEnc = (cEnc << 4) + nValue;
1102
0
        }
1103
0
        else
1104
0
        {
1105
0
            aBuffer.append( c );
1106
0
        }
1107
0
    }
1108
1109
0
    if( bEncoded )
1110
0
        rName = aBuffer.makeStringAndClear();
1111
0
    return bEncoded;
1112
0
}
1113
1114
bool XMLTransformerBase::NegPercent( OUString& rValue )
1115
0
{
1116
0
    bool bRet = false;
1117
0
    bool bNeg = false;
1118
0
    double nVal = 0;
1119
1120
0
    sal_Int32 nPos = 0;
1121
0
    sal_Int32 nLen = rValue.getLength();
1122
1123
    // skip white space
1124
0
    while( nPos < nLen && ' ' == rValue[nPos] )
1125
0
        nPos++;
1126
1127
0
    if( nPos < nLen && '-' == rValue[nPos] )
1128
0
    {
1129
0
        bNeg = true;
1130
0
        nPos++;
1131
0
    }
1132
1133
    // get number
1134
0
    while( nPos < nLen &&
1135
0
           '0' <= rValue[nPos] &&
1136
0
           '9' >= rValue[nPos] )
1137
0
    {
1138
        // TODO: check overflow!
1139
0
        nVal *= 10;
1140
0
        nVal += (rValue[nPos] - '0');
1141
0
        nPos++;
1142
0
    }
1143
0
    if( nPos < nLen && '.' == rValue[nPos] )
1144
0
    {
1145
0
        nPos++;
1146
0
        double nDiv = 1.;
1147
1148
0
        while( nPos < nLen &&
1149
0
               '0' <= rValue[nPos] &&
1150
0
               '9' >= rValue[nPos] )
1151
0
        {
1152
            // TODO: check overflow!
1153
0
            nDiv *= 10;
1154
0
            nVal += ( static_cast<double>(rValue[nPos] - '0') / nDiv );
1155
0
            nPos++;
1156
0
        }
1157
0
    }
1158
1159
    // skip white space
1160
0
    while( nPos < nLen && ' ' == rValue[nPos] )
1161
0
        nPos++;
1162
1163
0
    if( nPos < nLen && '%' == rValue[nPos] )
1164
0
    {
1165
0
        if( bNeg )
1166
0
               nVal = -nVal;
1167
0
        nVal += .5;
1168
1169
0
        sal_Int32 nIntVal = 100 - static_cast<sal_Int32>( nVal );
1170
1171
0
        rValue = OUString::number(nIntVal) + "%";
1172
1173
0
        bRet = true;
1174
0
    }
1175
1176
0
    return bRet;
1177
0
}
1178
1179
void XMLTransformerBase::AddNamespacePrefix( OUString& rName,
1180
                             sal_uInt16 nPrefix ) const
1181
0
{
1182
0
    rName = GetNamespaceMap().GetQNameByKey( nPrefix, rName, false );
1183
0
}
1184
1185
bool XMLTransformerBase::RemoveNamespacePrefix( OUString& rName,
1186
                            sal_uInt16 nPrefixOnly ) const
1187
0
{
1188
0
    OUString aLocalName;
1189
0
    sal_uInt16 nPrefix =
1190
0
        GetNamespaceMap().GetKeyByAttrValueQName(rName, &aLocalName);
1191
0
    bool bRet = XML_NAMESPACE_UNKNOWN != nPrefix &&
1192
0
                    (USHRT_MAX == nPrefixOnly || nPrefix == nPrefixOnly);
1193
0
    if( bRet )
1194
0
        rName = aLocalName;
1195
1196
0
    return bRet;
1197
0
}
1198
1199
bool XMLTransformerBase::ConvertURIToOASIS( OUString& rURI,
1200
                                        bool bSupportPackage ) const
1201
0
{
1202
0
    bool bRet = false;
1203
0
    if( !m_aExtPathPrefix.isEmpty() && !rURI.isEmpty() )
1204
0
    {
1205
0
        bool bRel = false;
1206
0
        switch( rURI[0] )
1207
0
        {
1208
0
        case '#':
1209
            // no rel path, but
1210
            // for package URIs, the '#' has to be removed
1211
0
            if( bSupportPackage )
1212
0
            {
1213
0
                rURI = rURI.copy( 1 );
1214
0
                bRet = true;
1215
0
            }
1216
0
            break;
1217
0
        case '/':
1218
            // no rel path; nothing to do
1219
0
            break;
1220
0
        case '.':
1221
            // a rel path; to keep URI simple, remove './', if there
1222
0
            bRel = true;
1223
0
            if( rURI.getLength() > 1 && '/' == rURI[1] )
1224
0
            {
1225
0
                rURI = rURI.copy( 2 );
1226
0
                bRet = true;
1227
0
            }
1228
0
            break;
1229
0
        default:
1230
            // check for a RFC2396 schema
1231
0
            {
1232
0
                bRel = true;
1233
0
                sal_Int32 nPos = 1;
1234
0
                sal_Int32 nLen = rURI.getLength();
1235
0
                while( nPos < nLen )
1236
0
                {
1237
0
                    switch( rURI[nPos] )
1238
0
                    {
1239
0
                    case '/':
1240
                        // a relative path segment
1241
0
                        nPos = nLen;    // leave loop
1242
0
                        break;
1243
0
                    case ':':
1244
                        // a schema
1245
0
                        bRel = false;
1246
0
                        nPos = nLen;    // leave loop
1247
0
                        break;
1248
0
                    default:
1249
                        // we don't care about any other characters
1250
0
                        break;
1251
0
                    }
1252
0
                    ++nPos;
1253
0
                }
1254
0
            }
1255
0
        }
1256
1257
0
        if( bRel )
1258
0
        {
1259
0
            rURI = m_aExtPathPrefix + rURI;
1260
0
            bRet = true;
1261
0
        }
1262
0
    }
1263
1264
0
    return bRet;
1265
0
}
1266
1267
bool XMLTransformerBase::ConvertURIToOOo( OUString& rURI,
1268
                                        bool bSupportPackage ) const
1269
0
{
1270
0
    bool bRet = false;
1271
0
    if( !rURI.isEmpty() )
1272
0
    {
1273
0
        bool bPackage = false;
1274
0
        switch( rURI[0] )
1275
0
        {
1276
0
        case '/':
1277
            // no rel path; nothing to do
1278
0
            break;
1279
0
        case '.':
1280
            // a rel path
1281
0
            if( rURI.startsWith( m_aExtPathPrefix ) )
1282
0
            {
1283
                // an external URI; remove '../'
1284
0
                rURI = rURI.copy( m_aExtPathPrefix.getLength() );
1285
0
                bRet = true;
1286
0
            }
1287
0
            else
1288
0
            {
1289
0
                bPackage = true;
1290
0
            }
1291
0
            break;
1292
0
        default:
1293
            // check for a RFC2396 schema
1294
0
            {
1295
0
                bPackage = true;
1296
0
                sal_Int32 nPos = 1;
1297
0
                sal_Int32 nLen = rURI.getLength();
1298
0
                while( nPos < nLen )
1299
0
                {
1300
0
                    switch( rURI[nPos] )
1301
0
                    {
1302
0
                    case '/':
1303
                        // a relative path segment within the package
1304
0
                        nPos = nLen - 1;    // leave loop
1305
0
                        break;
1306
0
                    case ':':
1307
                        // a schema
1308
0
                        bPackage = false;
1309
0
                        nPos = nLen - 1;    // leave loop
1310
0
                        break;
1311
0
                    default:
1312
                        // we don't care about any other characters
1313
0
                        break;
1314
0
                    }
1315
0
                    ++nPos;
1316
0
                }
1317
0
            }
1318
0
        }
1319
1320
0
        if( bPackage && bSupportPackage )
1321
0
        {
1322
0
            if( rURI.startsWith( "./" ) )
1323
0
                rURI = rURI.copy( 2 );
1324
0
            rURI = "#" + rURI;
1325
0
            bRet = true;
1326
0
        }
1327
0
    }
1328
1329
0
    return bRet;
1330
0
}
1331
1332
bool XMLTransformerBase::RenameAttributeValue(
1333
    OUString& rOutAttributeValue,
1334
    sal_Int32 nParam1,
1335
    sal_Int32 nParam2,
1336
    sal_Int32 nParam3 )
1337
0
{
1338
0
    return ( lcl_ConvertAttr( rOutAttributeValue, nParam1) ||
1339
0
             lcl_ConvertAttr( rOutAttributeValue, nParam2) ||
1340
0
             lcl_ConvertAttr( rOutAttributeValue, nParam3) );
1341
0
}
1342
1343
// static
1344
bool XMLTransformerBase::ConvertRNGDateTimeToISO( OUString& rDateTime )
1345
0
{
1346
0
    if( !rDateTime.isEmpty() &&
1347
0
        rDateTime.indexOf( '.' ) != -1 )
1348
0
    {
1349
0
        rDateTime = rDateTime.replace( '.', ',');
1350
0
        return true;
1351
0
    }
1352
1353
0
    return false;
1354
0
}
1355
1356
XMLTokenEnum XMLTransformerBase::GetToken( const OUString& rStr ) const
1357
0
{
1358
0
    XMLTransformerTokenMap::const_iterator aIter =
1359
0
        m_TokenMap.find( rStr );
1360
0
    if( aIter == m_TokenMap.end() )
1361
0
        return XML_TOKEN_END;
1362
0
    else
1363
0
        return (*aIter).second;
1364
0
}
1365
1366
1367
const XMLTransformerContext *XMLTransformerBase::GetCurrentContext() const
1368
0
{
1369
0
    OSL_ENSURE( !m_vContexts.empty(), "empty stack" );
1370
1371
1372
0
    return m_vContexts.empty() ? nullptr : m_vContexts.back().get();
1373
0
}
1374
1375
const XMLTransformerContext *XMLTransformerBase::GetAncestorContext(
1376
                                                        sal_uInt32 n ) const
1377
0
{
1378
0
    auto nSize = m_vContexts.size();
1379
1380
0
    OSL_ENSURE( nSize > n + 2 , "invalid context" );
1381
1382
0
    return nSize > n + 2 ? m_vContexts[nSize - (n + 2)].get() : nullptr;
1383
0
}
1384
1385
bool XMLTransformerBase::isWriter() const
1386
0
{
1387
0
    Reference< XServiceInfo > xSI( mxModel, UNO_QUERY );
1388
0
    return  xSI.is() &&
1389
0
        (   xSI->supportsService(u"com.sun.star.text.TextDocument"_ustr) ||
1390
0
            xSI->supportsService(u"com.sun.star.text.WebDocument"_ustr) ||
1391
0
            xSI->supportsService(u"com.sun.star.text.GlobalDocument"_ustr) );
1392
0
}
1393
1394
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */