Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/xmlscript/source/xml_helper/xml_impctx.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 <sal/config.h>
21
22
#include <xml_import.hxx>
23
24
#include <cppuhelper/implbase.hxx>
25
#include <cppuhelper/supportsservice.hxx>
26
#include <com/sun/star/container/NoSuchElementException.hpp>
27
#include <com/sun/star/xml/input/XAttributes.hpp>
28
#include <com/sun/star/lang/XInitialization.hpp>
29
#include <com/sun/star/uno/XComponentContext.hpp>
30
#include <com/sun/star/lang/XServiceInfo.hpp>
31
#include <sal/log.hxx>
32
#include <rtl/ref.hxx>
33
34
#include <memory>
35
#include <mutex>
36
#include <optional>
37
#include <unordered_map>
38
#include <vector>
39
40
using namespace ::com::sun::star;
41
using namespace ::com::sun::star::uno;
42
43
namespace xmlscript
44
{
45
46
const sal_Int32 UID_UNKNOWN = -1;
47
48
typedef std::unordered_map< OUString, sal_Int32 > t_OUString2LongMap;
49
50
namespace {
51
52
struct PrefixEntry
53
{
54
    ::std::vector< sal_Int32 > m_Uids;
55
56
    PrefixEntry()
57
0
        { m_Uids.reserve( 4 ); }
58
};
59
60
}
61
62
typedef std::unordered_map< OUString, PrefixEntry > t_OUString2PrefixMap;
63
64
namespace {
65
66
struct ElementEntry
67
{
68
    Reference< xml::input::XElement > m_xElement;
69
    ::std::vector< OUString > m_prefixes;
70
71
    ElementEntry()
72
0
        { m_prefixes.reserve( 2 ); }
73
};
74
75
class ExtendedAttributes;
76
77
class MGuard
78
{
79
    std::mutex * m_pMutex;
80
public:
81
    explicit MGuard( std::optional<std::mutex> & oMutex )
82
0
        : m_pMutex( oMutex ? &*oMutex : nullptr )
83
0
        { if (m_pMutex) m_pMutex->lock(); }
84
    ~MGuard() noexcept
85
0
        { if (m_pMutex) m_pMutex->unlock(); }
86
};
87
88
class DocumentHandlerImpl :
89
    public ::cppu::WeakImplHelper< xml::sax::XDocumentHandler,
90
                                    xml::input::XNamespaceMapping,
91
                                    lang::XInitialization,
92
                                    css::lang::XServiceInfo >
93
{
94
    friend class ExtendedAttributes;
95
96
    Reference< xml::input::XRoot > m_xRoot;
97
98
    t_OUString2LongMap m_URI2Uid;
99
    sal_Int32 m_uid_count;
100
101
    sal_Int32 m_nLastURI_lookup;
102
    OUString m_aLastURI_lookup;
103
104
    t_OUString2PrefixMap m_prefixes;
105
    sal_Int32 m_nLastPrefix_lookup;
106
    OUString m_aLastPrefix_lookup;
107
108
    std::vector< ElementEntry > m_elements;
109
    sal_Int32 m_nSkipElements;
110
111
    mutable std::optional<std::mutex> m_oMutex;
112
113
    inline Reference< xml::input::XElement > getCurrentElement() const;
114
115
    inline sal_Int32 getUidByURI( OUString const & rURI );
116
    inline sal_Int32 getUidByPrefix( OUString const & rPrefix );
117
118
    inline void pushPrefix(
119
        OUString const & rPrefix, OUString const & rURI );
120
    inline void popPrefix( OUString const & rPrefix );
121
122
    inline void getElementName(
123
        OUString const & rQName, sal_Int32 * pUid, OUString * pLocalName );
124
125
public:
126
    DocumentHandlerImpl(
127
        Reference< xml::input::XRoot > const & xRoot,
128
        bool bSingleThreadedUse );
129
130
    // XServiceInfo
131
    virtual OUString SAL_CALL getImplementationName() override;
132
    virtual sal_Bool SAL_CALL supportsService(
133
        OUString const & servicename ) override;
134
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
135
136
    // XInitialization
137
    virtual void SAL_CALL initialize(
138
        Sequence< Any > const & arguments ) override;
139
140
    // XDocumentHandler
141
    virtual void SAL_CALL startDocument() override;
142
    virtual void SAL_CALL endDocument() override;
143
    virtual void SAL_CALL startElement(
144
        OUString const & rQElementName,
145
        Reference< xml::sax::XAttributeList > const & xAttribs ) override;
146
    virtual void SAL_CALL endElement(
147
        OUString const & rQElementName ) override;
148
    virtual void SAL_CALL characters(
149
        OUString const & rChars ) override;
150
    virtual void SAL_CALL ignorableWhitespace(
151
        OUString const & rWhitespaces ) override;
152
    virtual void SAL_CALL processingInstruction(
153
        OUString const & rTarget, OUString const & rData ) override;
154
    virtual void SAL_CALL setDocumentLocator(
155
        Reference< xml::sax::XLocator > const & xLocator ) override;
156
157
    // XNamespaceMapping
158
    virtual sal_Int32 SAL_CALL getUidByUri( OUString const & Uri ) override;
159
    virtual OUString SAL_CALL getUriByUid( sal_Int32 Uid ) override;
160
};
161
162
}
163
164
constexpr OUString g_sXMLNS_PREFIX_UNKNOWN( u"<<< unknown prefix >>>"_ustr );
165
constexpr OUString g_sXMLNS( u"xmlns"_ustr );
166
167
168
DocumentHandlerImpl::DocumentHandlerImpl(
169
    Reference< xml::input::XRoot > const & xRoot,
170
    bool bSingleThreadedUse )
171
0
    : m_xRoot( xRoot ),
172
0
      m_uid_count( 0 ),
173
0
      m_nLastURI_lookup( UID_UNKNOWN ),
174
0
      m_aLastURI_lookup( u"<<< unknown URI >>>"_ustr ),
175
0
      m_nLastPrefix_lookup( UID_UNKNOWN ),
176
0
      m_aLastPrefix_lookup( u"<<< unknown URI >>>"_ustr ),
177
0
      m_nSkipElements( 0 )
178
0
{
179
0
    m_elements.reserve( 10 );
180
181
0
    if (! bSingleThreadedUse)
182
0
        m_oMutex.emplace();
183
0
}
184
185
inline Reference< xml::input::XElement >
186
DocumentHandlerImpl::getCurrentElement() const
187
0
{
188
0
    MGuard aGuard( m_oMutex );
189
0
    if (m_elements.empty())
190
0
        return Reference< xml::input::XElement >();
191
0
    else
192
0
        return m_elements.back().m_xElement;
193
0
}
194
195
inline sal_Int32 DocumentHandlerImpl::getUidByURI( OUString const & rURI )
196
0
{
197
0
    MGuard guard( m_oMutex );
198
0
    if (m_nLastURI_lookup == UID_UNKNOWN || m_aLastURI_lookup != rURI)
199
0
    {
200
0
        t_OUString2LongMap::const_iterator iFind( m_URI2Uid.find( rURI ) );
201
0
        if (iFind != m_URI2Uid.end()) // id found
202
0
        {
203
0
            m_nLastURI_lookup = iFind->second;
204
0
            m_aLastURI_lookup = rURI;
205
0
        }
206
0
        else
207
0
        {
208
0
            m_nLastURI_lookup = m_uid_count;
209
0
            ++m_uid_count;
210
0
            m_URI2Uid[ rURI ] = m_nLastURI_lookup;
211
0
            m_aLastURI_lookup = rURI;
212
0
        }
213
0
    }
214
0
    return m_nLastURI_lookup;
215
0
}
216
217
inline sal_Int32 DocumentHandlerImpl::getUidByPrefix(
218
    OUString const & rPrefix )
219
0
{
220
    // commonly the last added prefix is used often for several tags...
221
    // good guess
222
0
    if (m_nLastPrefix_lookup == UID_UNKNOWN || m_aLastPrefix_lookup != rPrefix)
223
0
    {
224
0
        t_OUString2PrefixMap::const_iterator iFind(
225
0
            m_prefixes.find( rPrefix ) );
226
0
        if (iFind != m_prefixes.end())
227
0
        {
228
0
            const PrefixEntry & rPrefixEntry = iFind->second;
229
0
            SAL_WARN_IF( rPrefixEntry.m_Uids.empty(), "xmlscript.xmlhelper", "rPrefixEntry.m_Uids is empty" );
230
0
            m_nLastPrefix_lookup = rPrefixEntry.m_Uids.back();
231
0
            m_aLastPrefix_lookup = rPrefix;
232
0
        }
233
0
        else
234
0
        {
235
0
            m_nLastPrefix_lookup = UID_UNKNOWN;
236
0
            m_aLastPrefix_lookup = g_sXMLNS_PREFIX_UNKNOWN;
237
0
        }
238
0
    }
239
0
    return m_nLastPrefix_lookup;
240
0
}
241
242
inline void DocumentHandlerImpl::pushPrefix(
243
    OUString const & rPrefix, OUString const & rURI )
244
0
{
245
    // lookup id for URI
246
0
    sal_Int32 nUid = getUidByURI( rURI );
247
248
    // mark prefix with id
249
0
    t_OUString2PrefixMap::iterator iFind( m_prefixes.find( rPrefix ) );
250
0
    if (iFind == m_prefixes.end()) // unused prefix
251
0
    {
252
0
        PrefixEntry aEntry;
253
0
        aEntry.m_Uids.push_back( nUid ); // latest id for prefix
254
0
        m_prefixes[rPrefix] = std::move(aEntry);
255
0
    }
256
0
    else
257
0
    {
258
0
        PrefixEntry& rEntry = iFind->second;
259
0
        SAL_WARN_IF(rEntry.m_Uids.empty(), "xmlscript.xmlhelper", "pEntry->m_Uids is empty");
260
0
        rEntry.m_Uids.push_back(nUid);
261
0
    }
262
263
0
    m_aLastPrefix_lookup = rPrefix;
264
0
    m_nLastPrefix_lookup = nUid;
265
0
}
266
267
inline void DocumentHandlerImpl::popPrefix(
268
    OUString const & rPrefix )
269
0
{
270
0
    t_OUString2PrefixMap::iterator iFind( m_prefixes.find( rPrefix ) );
271
0
    if (iFind != m_prefixes.end()) // unused prefix
272
0
    {
273
0
        PrefixEntry& rEntry = iFind->second;
274
0
        rEntry.m_Uids.pop_back(); // pop last id for prefix
275
0
        if (rEntry.m_Uids.empty()) // erase prefix key
276
0
        {
277
0
            m_prefixes.erase(iFind);
278
0
        }
279
0
    }
280
281
0
    m_nLastPrefix_lookup = UID_UNKNOWN;
282
0
    m_aLastPrefix_lookup = g_sXMLNS_PREFIX_UNKNOWN;
283
0
}
284
285
inline void DocumentHandlerImpl::getElementName(
286
    OUString const & rQName, sal_Int32 * pUid, OUString * pLocalName )
287
0
{
288
0
    sal_Int32 nColonPos = rQName.indexOf( ':' );
289
0
    *pLocalName = (nColonPos >= 0 ? rQName.copy( nColonPos +1 ) : rQName);
290
0
    *pUid = getUidByPrefix(
291
0
        nColonPos >= 0 ? rQName.copy( 0, nColonPos ) : OUString() );
292
0
}
293
294
namespace {
295
296
class ExtendedAttributes :
297
    public ::cppu::WeakImplHelper< xml::input::XAttributes >
298
{
299
    sal_Int32 const m_nAttributes;
300
    std::unique_ptr<sal_Int32[]> m_pUids;
301
    std::unique_ptr<OUString[]>  m_pLocalNames;
302
    std::unique_ptr<OUString[]>  m_pQNames;
303
    std::unique_ptr<OUString[]>  m_pValues;
304
305
public:
306
    inline ExtendedAttributes(
307
        sal_Int32 nAttributes,
308
        std::unique_ptr<sal_Int32[]> pUids,
309
        std::unique_ptr<OUString[]> pLocalNames,
310
        std::unique_ptr<OUString[]> pQNames,
311
        Reference< xml::sax::XAttributeList > const & xAttributeList );
312
313
    // XAttributes
314
    virtual sal_Int32 SAL_CALL getLength() override;
315
    virtual sal_Int32 SAL_CALL getIndexByQName(
316
        OUString const & rQName ) override;
317
    virtual sal_Int32 SAL_CALL getIndexByUidName(
318
        sal_Int32 nUid, OUString const & rLocalName ) override;
319
    virtual OUString SAL_CALL getQNameByIndex(
320
        sal_Int32 nIndex ) override;
321
    virtual sal_Int32 SAL_CALL getUidByIndex(
322
        sal_Int32 nIndex ) override;
323
    virtual OUString SAL_CALL getLocalNameByIndex(
324
        sal_Int32 nIndex ) override;
325
    virtual OUString SAL_CALL getValueByIndex(
326
        sal_Int32 nIndex ) override;
327
    virtual OUString SAL_CALL getValueByUidName(
328
        sal_Int32 nUid, OUString const & rLocalName ) override;
329
    virtual OUString SAL_CALL getTypeByIndex(
330
        sal_Int32 nIndex ) override;
331
};
332
333
}
334
335
inline ExtendedAttributes::ExtendedAttributes(
336
    sal_Int32 nAttributes,
337
    std::unique_ptr<sal_Int32[]> pUids,
338
    std::unique_ptr<OUString[]> pLocalNames, std::unique_ptr<OUString[]> pQNames,
339
    Reference< xml::sax::XAttributeList > const & xAttributeList )
340
0
    : m_nAttributes( nAttributes )
341
0
    , m_pUids( std::move(pUids) )
342
0
    , m_pLocalNames( std::move(pLocalNames) )
343
0
    , m_pQNames( std::move(pQNames) )
344
0
    , m_pValues( new OUString[ nAttributes ] )
345
0
{
346
0
    for ( sal_Int32 nPos = 0; nPos < nAttributes; ++nPos )
347
0
    {
348
0
        m_pValues[ nPos ] = xAttributeList->getValueByIndex( nPos );
349
0
    }
350
0
}
351
352
// XServiceInfo
353
354
OUString DocumentHandlerImpl::getImplementationName()
355
0
{
356
0
    return u"com.sun.star.comp.xml.input.SaxDocumentHandler"_ustr;
357
0
}
358
359
sal_Bool DocumentHandlerImpl::supportsService( OUString const & servicename )
360
0
{
361
0
    return cppu::supportsService(this, servicename);
362
0
}
363
364
Sequence< OUString > DocumentHandlerImpl::getSupportedServiceNames()
365
0
{
366
0
    return { u"com.sun.star.xml.input.SaxDocumentHandler"_ustr };
367
0
}
368
369
// XInitialization
370
371
void DocumentHandlerImpl::initialize(
372
    Sequence< Any > const & arguments )
373
0
{
374
0
    MGuard guard( m_oMutex );
375
0
    Reference< xml::input::XRoot > xRoot;
376
0
    if (arguments.getLength() != 1 ||
377
0
        !(arguments[ 0 ] >>= xRoot) ||
378
0
        !xRoot.is())
379
0
    {
380
0
        throw RuntimeException( u"missing root instance!"_ustr );
381
0
    }
382
0
    m_xRoot = std::move(xRoot);
383
0
}
384
385
// XNamespaceMapping
386
387
sal_Int32 DocumentHandlerImpl::getUidByUri( OUString const & Uri )
388
0
{
389
0
    sal_Int32 uid = getUidByURI( Uri );
390
0
    SAL_WARN_IF( uid == UID_UNKNOWN, "xmlscript.xmlhelper", "uid UNKNOWN");
391
0
    return uid;
392
0
}
393
394
OUString DocumentHandlerImpl::getUriByUid( sal_Int32 Uid )
395
0
{
396
0
    MGuard guard( m_oMutex );
397
0
    for (const auto& rURIUid : m_URI2Uid)
398
0
    {
399
0
        if (rURIUid.second == Uid)
400
0
            return rURIUid.first;
401
0
    }
402
0
    throw container::NoSuchElementException( u"no such xmlns uid!"_ustr , getXWeak() );
403
0
}
404
405
// XDocumentHandler
406
407
void DocumentHandlerImpl::startDocument()
408
0
{
409
0
    m_xRoot->startDocument( static_cast< xml::input::XNamespaceMapping * >( this ) );
410
0
}
411
412
void DocumentHandlerImpl::endDocument()
413
0
{
414
0
    m_xRoot->endDocument();
415
0
}
416
417
void DocumentHandlerImpl::startElement(
418
    OUString const & rQElementName,
419
    Reference< xml::sax::XAttributeList > const & xAttribs )
420
0
{
421
0
    Reference< xml::input::XElement > xCurrentElement;
422
0
    rtl::Reference< ExtendedAttributes > xAttributes;
423
0
    sal_Int32 nUid;
424
0
    OUString aLocalName;
425
0
    ElementEntry elementEntry;
426
427
0
    { // guard start:
428
0
    MGuard aGuard( m_oMutex );
429
    // currently skipping elements and waiting for end tags?
430
0
    if (m_nSkipElements > 0)
431
0
    {
432
0
        ++m_nSkipElements; // wait for another end tag
433
0
        SAL_INFO("xmlscript.xmlhelper", " no context given on createChildElement() => ignoring element \"" << rQElementName << "\" ...");
434
0
        return;
435
0
    }
436
437
0
    sal_Int16 nAttribs = xAttribs->getLength();
438
439
    // save all namespace ids
440
0
    std::unique_ptr<sal_Int32[]> pUids(new sal_Int32[ nAttribs ]);
441
0
    std::unique_ptr<OUString[]> pPrefixes(new OUString[ nAttribs ]);
442
0
    std::unique_ptr<OUString[]> pLocalNames(new OUString[ nAttribs ]);
443
0
    std::unique_ptr<OUString[]> pQNames(new OUString[ nAttribs ]);
444
445
    // first recognize all xmlns attributes
446
0
    sal_Int16 nPos;
447
0
    for ( nPos = 0; nPos < nAttribs; ++nPos )
448
0
    {
449
        // mark attribute to be collected further
450
        // on with attribute's uid and current prefix
451
0
        pUids[ nPos ] = 0; // modified
452
453
0
        pQNames[ nPos ] = xAttribs->getNameByIndex( nPos );
454
0
        OUString const & rQAttributeName = pQNames[ nPos ];
455
456
0
        if (rQAttributeName.startsWith( g_sXMLNS ))
457
0
        {
458
0
            if (rQAttributeName.getLength() == 5) // set default namespace
459
0
            {
460
0
                OUString aDefNamespacePrefix;
461
0
                pushPrefix(
462
0
                    aDefNamespacePrefix,
463
0
                    xAttribs->getValueByIndex( nPos ) );
464
0
                elementEntry.m_prefixes.push_back( aDefNamespacePrefix );
465
0
                pUids[ nPos ]          = UID_UNKNOWN;
466
0
                pPrefixes[ nPos ]      = g_sXMLNS;
467
0
                pLocalNames[ nPos ]    = aDefNamespacePrefix;
468
0
            }
469
0
            else if (':' == rQAttributeName[ 5 ]) // set prefix
470
0
            {
471
0
                OUString aPrefix( rQAttributeName.copy( 6 ) );
472
0
                pushPrefix( aPrefix, xAttribs->getValueByIndex( nPos ) );
473
0
                elementEntry.m_prefixes.push_back( aPrefix );
474
0
                pUids[ nPos ]          = UID_UNKNOWN;
475
0
                pPrefixes[ nPos ]      = g_sXMLNS;
476
0
                pLocalNames[ nPos ]    = aPrefix;
477
0
            }
478
            // else just a name starting with xmlns, but no prefix
479
0
        }
480
0
    }
481
482
    // now read out attribute prefixes (all namespace prefixes have been set)
483
0
    for ( nPos = 0; nPos < nAttribs; ++nPos )
484
0
    {
485
0
        if (pUids[ nPos ] >= 0) // no xmlns: attribute
486
0
        {
487
0
            OUString const & rQAttributeName = pQNames[ nPos ];
488
0
            SAL_WARN_IF(rQAttributeName.startsWith( "xmlns:" ), "xmlscript.xmlhelper", "### unexpected xmlns!" );
489
490
            // collect attribute's uid and current prefix
491
0
            sal_Int32 nColonPos = rQAttributeName.indexOf( ':' );
492
0
            if (nColonPos >= 0)
493
0
            {
494
0
                pPrefixes[ nPos ] = rQAttributeName.copy( 0, nColonPos );
495
0
                pLocalNames[ nPos ] = rQAttributeName.copy( nColonPos +1 );
496
0
            }
497
0
            else
498
0
            {
499
0
                pPrefixes[ nPos ].clear();
500
0
                pLocalNames[ nPos ] = rQAttributeName;
501
                // leave local names unmodified
502
0
            }
503
0
            pUids[ nPos ] = getUidByPrefix( pPrefixes[ nPos ] );
504
0
        }
505
0
    }
506
0
    pPrefixes.reset();
507
    // ownership of arrays belongs to attribute list
508
0
    xAttributes = new ExtendedAttributes(nAttribs, std::move(pUids), std::move(pLocalNames),
509
0
                                         std::move(pQNames), xAttribs);
510
511
0
    getElementName( rQElementName, &nUid, &aLocalName );
512
513
    // create new child context and append to list
514
0
    if (! m_elements.empty())
515
0
        xCurrentElement = m_elements.back().m_xElement;
516
0
    } // :guard end
517
518
0
    if (xCurrentElement.is())
519
0
    {
520
0
        elementEntry.m_xElement =
521
0
            xCurrentElement->startChildElement( nUid, aLocalName, xAttributes );
522
0
    }
523
0
    else
524
0
    {
525
0
        elementEntry.m_xElement =
526
0
            m_xRoot->startRootElement( nUid, aLocalName, xAttributes );
527
0
    }
528
529
0
    {
530
0
    MGuard aGuard( m_oMutex );
531
0
    if (elementEntry.m_xElement.is())
532
0
    {
533
0
        m_elements.push_back( std::move(elementEntry) );
534
0
    }
535
0
    else
536
0
    {
537
0
        ++m_nSkipElements;
538
539
        // pop prefixes
540
0
        for (sal_Int32 nPos = elementEntry.m_prefixes.size(); nPos--;)
541
0
            popPrefix(elementEntry.m_prefixes[nPos]);
542
543
0
        SAL_INFO("xmlscript.xmlhelper", " no context given on createChildElement() => ignoring element \"" << rQElementName << "\" ...");
544
0
    }
545
0
    }
546
0
}
547
548
void DocumentHandlerImpl::endElement(
549
    OUString const & rQElementName )
550
0
{
551
0
    Reference< xml::input::XElement > xCurrentElement;
552
0
    {
553
0
        MGuard aGuard( m_oMutex );
554
0
        if (m_nSkipElements)
555
0
        {
556
0
            --m_nSkipElements;
557
0
            SAL_INFO("xmlscript.xmlhelper", "### received endElement() for \"" << rQElementName << "\".");
558
0
            return;
559
0
        }
560
561
        // popping context
562
0
        SAL_WARN_IF( m_elements.empty(), "xmlscript.xmlhelper", "m_elements is empty" );
563
0
        ElementEntry& rEntry = m_elements.back();
564
0
        xCurrentElement = rEntry.m_xElement;
565
566
#if OSL_DEBUG_LEVEL > 0
567
        sal_Int32 nUid;
568
        OUString aLocalName;
569
        getElementName( rQElementName, &nUid, &aLocalName );
570
        SAL_WARN_IF( xCurrentElement->getLocalName() != aLocalName, "xmlscript.xmlhelper", "xCurrentElement->getLocalName() != aLocalName" );
571
        SAL_WARN_IF( xCurrentElement->getUid() != nUid, "xmlscript.xmlhelper", "xCurrentElement->getUid() != nUid" );
572
#endif
573
574
        // pop prefixes
575
0
        for ( sal_Int32 nPos = rEntry.m_prefixes.size(); nPos--; )
576
0
        {
577
0
            popPrefix( rEntry.m_prefixes[ nPos ] );
578
0
        }
579
0
        m_elements.pop_back();
580
0
    }
581
0
    xCurrentElement->endElement();
582
0
}
583
584
void DocumentHandlerImpl::characters( OUString const & rChars )
585
0
{
586
0
    Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
587
0
    if (xCurrentElement.is())
588
0
        xCurrentElement->characters( rChars );
589
0
}
590
591
void DocumentHandlerImpl::ignorableWhitespace(
592
    OUString const & rWhitespaces )
593
0
{
594
0
    Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
595
0
    if (xCurrentElement.is())
596
0
        xCurrentElement->ignorableWhitespace( rWhitespaces );
597
0
}
598
599
void DocumentHandlerImpl::processingInstruction(
600
    OUString const & rTarget, OUString const & rData )
601
0
{
602
0
    Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
603
0
    if (xCurrentElement.is())
604
0
        xCurrentElement->processingInstruction( rTarget, rData );
605
0
    else
606
0
        m_xRoot->processingInstruction( rTarget, rData );
607
0
}
608
609
void DocumentHandlerImpl::setDocumentLocator(
610
    Reference< xml::sax::XLocator > const & xLocator )
611
0
{
612
0
    m_xRoot->setDocumentLocator( xLocator );
613
0
}
614
615
// XAttributes
616
617
sal_Int32 ExtendedAttributes::getIndexByQName( OUString const & rQName )
618
0
{
619
0
    for ( sal_Int32 nPos = m_nAttributes; nPos--; )
620
0
    {
621
0
        if (m_pQNames[ nPos ] == rQName)
622
0
        {
623
0
            return nPos;
624
0
        }
625
0
    }
626
0
    return -1;
627
0
}
628
629
sal_Int32 ExtendedAttributes::getLength()
630
0
{
631
0
    return m_nAttributes;
632
0
}
633
634
OUString ExtendedAttributes::getLocalNameByIndex( sal_Int32 nIndex )
635
0
{
636
0
    if (nIndex < m_nAttributes)
637
0
        return m_pLocalNames[ nIndex ];
638
0
    else
639
0
        return OUString();
640
0
}
641
642
OUString ExtendedAttributes::getQNameByIndex( sal_Int32 nIndex )
643
0
{
644
0
    if (nIndex < m_nAttributes)
645
0
        return m_pQNames[ nIndex ];
646
0
    else
647
0
        return OUString();
648
0
}
649
650
OUString ExtendedAttributes::getTypeByIndex( sal_Int32 nIndex )
651
0
{
652
0
    SAL_WARN_IF( nIndex >= m_nAttributes , "xmlscript.xmlhelper", "nIndex is bigger than m_nAttributes");
653
0
    return OUString(); // unsupported
654
0
}
655
656
OUString ExtendedAttributes::getValueByIndex( sal_Int32 nIndex )
657
0
{
658
0
    if (nIndex < m_nAttributes)
659
0
        return m_pValues[ nIndex ];
660
0
    else
661
0
        return OUString();
662
0
}
663
664
sal_Int32 ExtendedAttributes::getIndexByUidName(
665
    sal_Int32 nUid, OUString const & rLocalName )
666
0
{
667
0
    for ( sal_Int32 nPos = m_nAttributes; nPos--; )
668
0
    {
669
0
        if (m_pUids[ nPos ] == nUid && m_pLocalNames[ nPos ] == rLocalName)
670
0
        {
671
0
            return nPos;
672
0
        }
673
0
    }
674
0
    return -1;
675
0
}
676
677
sal_Int32 ExtendedAttributes::getUidByIndex( sal_Int32 nIndex )
678
0
{
679
0
    if (nIndex < m_nAttributes)
680
0
        return m_pUids[ nIndex ];
681
0
    else
682
0
        return -1;
683
0
}
684
685
OUString ExtendedAttributes::getValueByUidName(
686
    sal_Int32 nUid, OUString const & rLocalName )
687
0
{
688
0
    for ( sal_Int32 nPos = m_nAttributes; nPos--; )
689
0
    {
690
0
        if (m_pUids[ nPos ] == nUid && m_pLocalNames[ nPos ] == rLocalName)
691
0
        {
692
0
            return m_pValues[ nPos ];
693
0
        }
694
0
    }
695
0
    return OUString();
696
0
}
697
698
Reference< xml::sax::XDocumentHandler > createDocumentHandler(
699
    Reference< xml::input::XRoot > const & xRoot )
700
0
{
701
0
    SAL_WARN_IF( !xRoot.is(), "xmlscript.xmlhelper", "xRoot is NULL" );
702
0
    if (xRoot.is())
703
0
    {
704
0
        return new DocumentHandlerImpl(xRoot, true /* mt use */);
705
0
    }
706
0
    return Reference< xml::sax::XDocumentHandler >();
707
0
}
708
709
}
710
711
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
712
com_sun_star_comp_xml_input_SaxDocumentHandler_get_implementation(
713
    css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const& )
714
0
{
715
0
    return cppu::acquire(new xmlscript::DocumentHandlerImpl({}, false /* mt use */));
716
0
}
717
718
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */