Coverage Report

Created: 2026-07-10 11:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sax/source/expatwrap/sax_expat.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 <string.h>
21
#include <cassert>
22
#include <memory>
23
#include <mutex>
24
#include <utility>
25
#include <string_view>
26
#include <vector>
27
28
29
#include <com/sun/star/lang/XServiceInfo.hpp>
30
#include <com/sun/star/lang/XInitialization.hpp>
31
#include <com/sun/star/uno/XComponentContext.hpp>
32
#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
33
#include <com/sun/star/xml/sax/XParser.hpp>
34
#include <com/sun/star/xml/sax/SAXParseException.hpp>
35
#include <com/sun/star/io/IOException.hpp>
36
#include <com/sun/star/io/XSeekable.hpp>
37
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
38
39
#include <comphelper/attributelist.hxx>
40
#include <cppuhelper/weak.hxx>
41
#include <cppuhelper/implbase.hxx>
42
#include <cppuhelper/supportsservice.hxx>
43
#include <rtl/ref.hxx>
44
#include <sal/log.hxx>
45
46
#include <expat.h>
47
#include <xml2utf.hxx>
48
49
using namespace ::cppu;
50
using namespace ::com::sun::star::lang;
51
using namespace ::com::sun::star::xml::sax;
52
using namespace ::com::sun::star::io;
53
54
55
namespace {
56
57
1.21M
#define XML_CHAR_TO_OUSTRING(x) OUString(x , strlen( x ), RTL_TEXTENCODING_UTF8)
58
#define XML_CHAR_N_TO_USTRING(x,n) OUString(x,n, RTL_TEXTENCODING_UTF8 )
59
60
61
/*
62
* The following macro encapsulates any call to an event handler.
63
* It ensures, that exceptions thrown by the event handler are
64
* treated properly.
65
*/
66
#define CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(pThis,call) \
67
634k
    if( ! pThis->bExceptionWasThrown ) { \
68
633k
        try {\
69
633k
            pThis->call;\
70
633k
        }\
71
633k
        catch( const SAXParseException &e ) {\
72
0
            callErrorHandler( pThis ,  e );\
73
0
         }\
74
633k
        catch( const SAXException &e ) {\
75
28
            callErrorHandler( pThis , SAXParseException(\
76
28
                                            e.Message, \
77
28
                                            e.Context, \
78
28
                                            e.WrappedException,\
79
28
                                            pThis->rDocumentLocator->getPublicId(),\
80
28
                                            pThis->rDocumentLocator->getSystemId(),\
81
28
                                            pThis->rDocumentLocator->getLineNumber(),\
82
28
                                            pThis->rDocumentLocator->getColumnNumber()\
83
28
                                     ) );\
84
28
        }\
85
633k
        catch( const css::uno::RuntimeException &e ) {\
86
0
            pThis->bExceptionWasThrown = true; \
87
0
            pThis->bRTExceptionWasThrown = true; \
88
0
            pImpl->rtexception = e; \
89
0
        }\
90
633k
        catch( const css::uno::Exception &e ) {\
91
0
            pThis->bExceptionWasThrown = true; \
92
0
            pThis->bRTExceptionWasThrown = true; \
93
0
            pImpl->rtexception = WrappedTargetRuntimeException(u"Non-runtime UNO exception caught during parse"_ustr, e.Context, css::uno::Any(e)); \
94
0
        }\
95
633k
    }\
96
634k
    ((void)0)
97
98
99
class SaxExpatParser_Impl;
100
101
// This class implements the external Parser interface
102
class SaxExpatParser
103
    : public WeakImplHelper< XInitialization
104
                            , XServiceInfo
105
                            , XParser >
106
{
107
108
public:
109
    SaxExpatParser();
110
111
    // css::lang::XInitialization:
112
    virtual void SAL_CALL initialize(css::uno::Sequence<css::uno::Any> const& rArguments) override;
113
114
    // The SAX-Parser-Interface
115
    virtual void SAL_CALL parseStream(  const InputSource& structSource) override;
116
    virtual void SAL_CALL setDocumentHandler(const css::uno::Reference< XDocumentHandler > & xHandler) override;
117
118
    virtual void SAL_CALL setErrorHandler(const css::uno::Reference< XErrorHandler > & xHandler) override;
119
    virtual void SAL_CALL setDTDHandler(const css::uno::Reference < XDTDHandler > & xHandler) override;
120
    virtual void SAL_CALL setEntityResolver(const css::uno::Reference<  XEntityResolver >& xResolver) override;
121
122
    virtual void SAL_CALL setLocale( const Locale &locale ) override;
123
124
public: // XServiceInfo
125
    OUString                     SAL_CALL getImplementationName() override;
126
    css::uno::Sequence< OUString >         SAL_CALL getSupportedServiceNames() override;
127
    sal_Bool                     SAL_CALL supportsService(const OUString& ServiceName) override;
128
129
private:
130
    std::unique_ptr<SaxExpatParser_Impl>   m_pImpl;
131
};
132
133
134
// Entity binds all information needed for a single file
135
struct Entity
136
{
137
    InputSource         structSource;
138
    XML_Parser          pParser;
139
    sax_expatwrap::XMLFile2UTFConverter converter;
140
};
141
142
class LocatorImpl;
143
class SaxExpatParser_Impl
144
{
145
public: // module scope
146
    std::mutex aMutex;
147
    bool m_bEnableDoS; // fdo#60471 thank you Adobe Illustrator
148
149
    css::uno::Reference< XDocumentHandler >   rDocumentHandler;
150
    css::uno::Reference< XExtendedDocumentHandler > rExtendedDocumentHandler;
151
152
    css::uno::Reference< XErrorHandler >  rErrorHandler;
153
    css::uno::Reference< XDTDHandler >    rDTDHandler;
154
    css::uno::Reference< XEntityResolver > rEntityResolver;
155
    rtl::Reference < LocatorImpl >        rDocumentLocator;
156
157
158
    rtl::Reference < comphelper::AttributeList > rAttrList;
159
160
    // External entity stack
161
    std::vector<struct Entity>   vecEntity;
162
    void pushEntity( Entity &&entity )
163
40.8k
        { vecEntity.push_back( std::move(entity) ); }
164
    void popEntity()
165
40.8k
        { vecEntity.pop_back( ); }
166
    struct Entity &getEntity()
167
245k
        { return vecEntity.back(); }
168
169
170
    // Exception cannot be thrown through the C-XmlParser (possible resource leaks),
171
    // therefore the exception must be saved somewhere.
172
    SAXParseException   exception;
173
    css::uno::RuntimeException    rtexception;
174
    bool                bExceptionWasThrown;
175
    bool                bRTExceptionWasThrown;
176
177
public:
178
    SaxExpatParser_Impl()
179
40.8k
        : m_bEnableDoS(false)
180
40.8k
        , bExceptionWasThrown(false)
181
40.8k
        , bRTExceptionWasThrown(false)
182
40.8k
    {
183
40.8k
    }
184
185
    // the C-Callbacks for the expat parser
186
    void static callbackStartElement(void *userData, const XML_Char *name , const XML_Char **atts);
187
    void static callbackEndElement(void *userData, const XML_Char *name);
188
    void static callbackCharacters( void *userData , const XML_Char *s , int nLen );
189
    void static callbackProcessingInstruction(  void *userData ,
190
                                                const XML_Char *sTarget ,
191
                                                const XML_Char *sData );
192
193
    void static callbackEntityDecl( void *userData ,
194
                                    const XML_Char *entityName,
195
                                    int is_parameter_entity,
196
                                    const XML_Char *value,
197
                                    int value_length,
198
                                    const XML_Char *base,
199
                                    const XML_Char *systemId,
200
                                    const XML_Char *publicId,
201
                                    const XML_Char *notationName);
202
203
    void static callbackNotationDecl(   void *userData,
204
                                        const XML_Char *notationName,
205
                                        const XML_Char *base,
206
                                        const XML_Char *systemId,
207
                                        const XML_Char *publicId);
208
209
    bool static callbackExternalEntityRef(   XML_Parser parser,
210
                                            const XML_Char *openEntityNames,
211
                                            const XML_Char *base,
212
                                            const XML_Char *systemId,
213
                                            const XML_Char *publicId);
214
215
    int static callbackUnknownEncoding(void *encodingHandlerData,
216
                                                  const XML_Char *name,
217
                                                  XML_Encoding *info);
218
219
    void static callbackDefault( void *userData,  const XML_Char *s,  int len);
220
221
    void static callbackStartCDATA( void *userData );
222
    void static callbackEndCDATA( void *userData );
223
    void static callbackComment( void *userData , const XML_Char *s );
224
    void static callErrorHandler( SaxExpatParser_Impl *pImpl , const SAXParseException &e );
225
226
public:
227
    void parse();
228
};
229
230
extern "C"
231
{
232
    static void call_callbackStartElement(void *userData, const XML_Char *name , const XML_Char **atts)
233
306k
    {
234
306k
        SaxExpatParser_Impl::callbackStartElement(userData,name,atts);
235
306k
    }
236
    static void call_callbackEndElement(void *userData, const XML_Char *name)
237
290k
    {
238
290k
        SaxExpatParser_Impl::callbackEndElement(userData,name);
239
290k
    }
240
    static void call_callbackCharacters( void *userData , const XML_Char *s , int nLen )
241
36.2k
    {
242
36.2k
        SaxExpatParser_Impl::callbackCharacters(userData,s,nLen);
243
36.2k
    }
244
    static void call_callbackProcessingInstruction(void *userData,const XML_Char *sTarget,const XML_Char *sData )
245
945
    {
246
945
        SaxExpatParser_Impl::callbackProcessingInstruction(userData,sTarget,sData );
247
945
    }
248
    static void call_callbackEntityDecl(void *userData ,
249
                                        const XML_Char *entityName,
250
                                        int is_parameter_entity,
251
                                        const XML_Char *value,
252
                                        int value_length,
253
                                        const XML_Char *base,
254
                                        const XML_Char *systemId,
255
                                        const XML_Char *publicId,
256
                                        const XML_Char *notationName)
257
2
    {
258
2
        SaxExpatParser_Impl::callbackEntityDecl(userData, entityName,
259
2
                is_parameter_entity, value, value_length,
260
2
                base, systemId, publicId, notationName);
261
2
    }
262
    static void call_callbackNotationDecl(void *userData,
263
                                          const XML_Char *notationName,
264
                                          const XML_Char *base,
265
                                          const XML_Char *systemId,
266
                                          const XML_Char *publicId)
267
0
    {
268
0
        SaxExpatParser_Impl::callbackNotationDecl(userData,notationName,base,systemId,publicId);
269
0
    }
270
    static int call_callbackExternalEntityRef(XML_Parser parser,
271
                                              const XML_Char *openEntityNames,
272
                                              const XML_Char *base,
273
                                              const XML_Char *systemId,
274
                                              const XML_Char *publicId)
275
0
    {
276
0
        return SaxExpatParser_Impl::callbackExternalEntityRef(parser,openEntityNames,base,systemId,publicId);
277
0
    }
278
    static int call_callbackUnknownEncoding(void *encodingHandlerData,
279
                                              const XML_Char *name,
280
                                            XML_Encoding *info)
281
1
    {
282
1
        return SaxExpatParser_Impl::callbackUnknownEncoding(encodingHandlerData,name,info);
283
1
    }
284
    static void call_callbackDefault( void *userData,  const XML_Char *s,  int len)
285
0
    {
286
0
        SaxExpatParser_Impl::callbackDefault(userData,s,len);
287
0
    }
288
    static void call_callbackStartCDATA( void *userData )
289
0
    {
290
0
        SaxExpatParser_Impl::callbackStartCDATA(userData);
291
0
    }
292
    static void call_callbackEndCDATA( void *userData )
293
0
    {
294
0
        SaxExpatParser_Impl::callbackEndCDATA(userData);
295
0
    }
296
    static void call_callbackComment( void *userData , const XML_Char *s )
297
0
    {
298
0
        SaxExpatParser_Impl::callbackComment(userData,s);
299
0
    }
300
}
301
302
303
// LocatorImpl
304
305
class LocatorImpl :
306
    public WeakImplHelper< XLocator, css::io::XSeekable >
307
    // should use a different interface for stream positions!
308
{
309
public:
310
    explicit LocatorImpl(SaxExpatParser_Impl *p)
311
40.8k
        : m_pParser(p)
312
40.8k
    {
313
40.8k
    }
314
315
public: //XLocator
316
    virtual sal_Int32 SAL_CALL getColumnNumber() override
317
12.5k
    {
318
12.5k
        return XML_GetCurrentColumnNumber( m_pParser->getEntity().pParser );
319
12.5k
    }
320
    virtual sal_Int32 SAL_CALL getLineNumber() override
321
25.1k
    {
322
25.1k
        return XML_GetCurrentLineNumber( m_pParser->getEntity().pParser );
323
25.1k
    }
324
    virtual OUString SAL_CALL getPublicId() override
325
12.5k
    {
326
12.5k
        return m_pParser->getEntity().structSource.sPublicId;
327
12.5k
    }
328
    virtual OUString SAL_CALL getSystemId() override
329
25.1k
    {
330
25.1k
        return m_pParser->getEntity().structSource.sSystemId;
331
25.1k
    }
332
333
    // XSeekable (only for getPosition)
334
335
    virtual void SAL_CALL seek( sal_Int64 ) override
336
0
    {
337
0
    }
338
    virtual sal_Int64 SAL_CALL getPosition() override
339
0
    {
340
0
        return XML_GetCurrentByteIndex( m_pParser->getEntity().pParser );
341
0
    }
342
    virtual ::sal_Int64 SAL_CALL getLength() override
343
0
    {
344
0
        return 0;
345
0
    }
346
347
private:
348
349
    SaxExpatParser_Impl *m_pParser;
350
};
351
352
353
SaxExpatParser::SaxExpatParser(  )
354
40.8k
{
355
40.8k
    m_pImpl.reset( new SaxExpatParser_Impl );
356
357
40.8k
    m_pImpl->rDocumentLocator = new LocatorImpl( m_pImpl.get() );
358
359
    // Performance-improvement; handing out the same object with every call of
360
    // the startElement callback is allowed (see sax-specification):
361
40.8k
    m_pImpl->rAttrList = new comphelper::AttributeList;
362
363
40.8k
    m_pImpl->bExceptionWasThrown = false;
364
40.8k
    m_pImpl->bRTExceptionWasThrown = false;
365
40.8k
}
366
367
// css::lang::XInitialization:
368
void SAL_CALL
369
SaxExpatParser::initialize(css::uno::Sequence< css::uno::Any > const& rArguments)
370
12.4k
{
371
    // possible arguments: a string "DoSmeplease"
372
12.4k
    if (rArguments.hasElements())
373
12.4k
    {
374
12.4k
        OUString str;
375
12.4k
        if ((rArguments[0] >>= str) && "DoSmeplease" == str)
376
12.4k
        {
377
12.4k
            std::unique_lock guard( m_pImpl->aMutex );
378
12.4k
            m_pImpl->m_bEnableDoS = true;
379
12.4k
        }
380
12.4k
    }
381
12.4k
}
382
383
class ParserCleanup
384
{
385
private:
386
    SaxExpatParser_Impl& m_rParser;
387
    XML_Parser m_xmlParser;
388
public:
389
    ParserCleanup(SaxExpatParser_Impl& rParser, XML_Parser xmlParser)
390
40.8k
        : m_rParser(rParser)
391
40.8k
        , m_xmlParser(xmlParser)
392
40.8k
    {
393
40.8k
    }
394
    ~ParserCleanup()
395
40.8k
    {
396
40.8k
        m_rParser.popEntity();
397
        //XML_ParserFree accepts a null arg
398
40.8k
        XML_ParserFree(m_xmlParser);
399
40.8k
    }
400
};
401
402
/***************
403
*
404
* parseStream does Parser-startup initializations. The SaxExpatParser_Impl::parse() method does
405
* the file-specific initialization work. (During a parser run, external files may be opened)
406
*
407
****************/
408
void SaxExpatParser::parseStream(   const InputSource& structSource)
409
40.8k
{
410
    // Only one text at one time
411
40.8k
    std::unique_lock guard( m_pImpl->aMutex );
412
413
414
40.8k
    struct Entity entity;
415
40.8k
    entity.structSource = structSource;
416
417
40.8k
    if( ! entity.structSource.aInputStream.is() )
418
0
    {
419
0
        throw SAXException(u"No input source"_ustr,
420
0
                            css::uno::Reference< css::uno::XInterface > () , css::uno::Any() );
421
0
    }
422
423
40.8k
    entity.converter.setInputStream( entity.structSource.aInputStream );
424
40.8k
    if( !entity.structSource.sEncoding.isEmpty() )
425
0
    {
426
0
        entity.converter.setEncoding(
427
0
            OUStringToOString( entity.structSource.sEncoding , RTL_TEXTENCODING_ASCII_US ) );
428
0
    }
429
430
    // create parser with proper encoding
431
40.8k
    entity.pParser = XML_ParserCreate( nullptr );
432
40.8k
    if( ! entity.pParser )
433
0
    {
434
0
        throw SAXException(u"Couldn't create parser"_ustr,
435
0
                            css::uno::Reference< css::uno::XInterface > (), css::uno::Any() );
436
0
    }
437
438
    // set all necessary C-Callbacks
439
40.8k
    XML_SetUserData( entity.pParser, m_pImpl.get() );
440
40.8k
    XML_SetElementHandler(  entity.pParser ,
441
40.8k
                            call_callbackStartElement ,
442
40.8k
                            call_callbackEndElement );
443
40.8k
    XML_SetCharacterDataHandler( entity.pParser , call_callbackCharacters );
444
40.8k
    XML_SetProcessingInstructionHandler(entity.pParser ,
445
40.8k
                                        call_callbackProcessingInstruction );
446
40.8k
    if (!m_pImpl->m_bEnableDoS)
447
28.4k
    {
448
28.4k
        XML_SetEntityDeclHandler(entity.pParser, call_callbackEntityDecl);
449
28.4k
    }
450
40.8k
    XML_SetNotationDeclHandler( entity.pParser, call_callbackNotationDecl );
451
40.8k
    XML_SetExternalEntityRefHandler(    entity.pParser,
452
40.8k
                                        call_callbackExternalEntityRef);
453
40.8k
    XML_SetUnknownEncodingHandler( entity.pParser,  call_callbackUnknownEncoding ,nullptr);
454
455
40.8k
    if( m_pImpl->rExtendedDocumentHandler.is() ) {
456
457
        // These handlers just delegate calls to the ExtendedHandler. If no extended handler is
458
        // given, these callbacks can be ignored
459
0
        XML_SetDefaultHandlerExpand( entity.pParser, call_callbackDefault );
460
0
        XML_SetCommentHandler( entity.pParser, call_callbackComment );
461
0
        XML_SetCdataSectionHandler(     entity.pParser ,
462
0
                                        call_callbackStartCDATA ,
463
0
                                         call_callbackEndCDATA );
464
0
    }
465
466
467
40.8k
    m_pImpl->exception = SAXParseException();
468
40.8k
    auto const xmlParser = entity.pParser;
469
40.8k
    m_pImpl->pushEntity( std::move(entity) );
470
471
40.8k
    ParserCleanup aEnsureFree(*m_pImpl, xmlParser);
472
473
    // start the document
474
40.8k
    if( m_pImpl->rDocumentHandler.is() ) {
475
40.8k
        m_pImpl->rDocumentHandler->setDocumentLocator( m_pImpl->rDocumentLocator );
476
40.8k
        m_pImpl->rDocumentHandler->startDocument();
477
40.8k
    }
478
479
40.8k
    m_pImpl->parse();
480
481
    // finish document
482
40.8k
    if( m_pImpl->rDocumentHandler.is() ) {
483
28.3k
        m_pImpl->rDocumentHandler->endDocument();
484
28.3k
    }
485
40.8k
}
486
487
void SaxExpatParser::setDocumentHandler(const css::uno::Reference< XDocumentHandler > & xHandler)
488
69.2k
{
489
69.2k
    m_pImpl->rDocumentHandler = xHandler;
490
69.2k
    m_pImpl->rExtendedDocumentHandler =
491
69.2k
        css::uno::Reference< XExtendedDocumentHandler >( xHandler , css::uno::UNO_QUERY );
492
69.2k
}
493
494
void SaxExpatParser::setErrorHandler(const css::uno::Reference< XErrorHandler > & xHandler)
495
0
{
496
0
    m_pImpl->rErrorHandler = xHandler;
497
0
}
498
499
void SaxExpatParser::setDTDHandler(const css::uno::Reference< XDTDHandler > & xHandler)
500
0
{
501
0
    m_pImpl->rDTDHandler = xHandler;
502
0
}
503
504
void SaxExpatParser::setEntityResolver(const css::uno::Reference < XEntityResolver > & xResolver)
505
0
{
506
0
    m_pImpl->rEntityResolver = xResolver;
507
0
}
508
509
510
void SaxExpatParser::setLocale( const Locale & )
511
0
{
512
    // not implemented
513
0
}
514
515
// XServiceInfo
516
OUString SaxExpatParser::getImplementationName()
517
0
{
518
0
    return u"com.sun.star.comp.extensions.xml.sax.ParserExpat"_ustr;
519
0
}
520
521
// XServiceInfo
522
sal_Bool SaxExpatParser::supportsService(const OUString& ServiceName)
523
0
{
524
0
    return cppu::supportsService(this, ServiceName);
525
0
}
526
527
// XServiceInfo
528
css::uno::Sequence< OUString > SaxExpatParser::getSupportedServiceNames()
529
0
{
530
0
    return { u"com.sun.star.xml.sax.Parser"_ustr };
531
0
}
532
533
534
/*---------------------------------------
535
*
536
* Helper functions and classes
537
*
538
*
539
*-------------------------------------------*/
540
OUString getErrorMessage( XML_Error xmlE, std::u16string_view sSystemId , sal_Int32 nLine )
541
12.5k
{
542
12.5k
    OUString Message;
543
12.5k
    if( XML_ERROR_NONE == xmlE ) {
544
14
        Message = "No";
545
14
    }
546
12.5k
    else if( XML_ERROR_NO_MEMORY == xmlE ) {
547
0
        Message = "no memory";
548
0
    }
549
12.5k
    else if( XML_ERROR_SYNTAX == xmlE ) {
550
84
        Message = "syntax";
551
84
    }
552
12.4k
    else if( XML_ERROR_NO_ELEMENTS == xmlE ) {
553
1.31k
        Message = "no elements";
554
1.31k
    }
555
11.1k
    else if( XML_ERROR_INVALID_TOKEN == xmlE ) {
556
2.56k
        Message = "invalid token";
557
2.56k
    }
558
8.56k
    else if( XML_ERROR_UNCLOSED_TOKEN == xmlE ) {
559
8.26k
        Message = "unclosed token";
560
8.26k
    }
561
298
    else if( XML_ERROR_PARTIAL_CHAR == xmlE ) {
562
0
        Message = "partial char";
563
0
    }
564
298
    else if( XML_ERROR_TAG_MISMATCH == xmlE ) {
565
93
        Message = "tag mismatch";
566
93
    }
567
205
    else if( XML_ERROR_DUPLICATE_ATTRIBUTE == xmlE ) {
568
0
        Message = "duplicate attribute";
569
0
    }
570
205
    else if( XML_ERROR_JUNK_AFTER_DOC_ELEMENT == xmlE ) {
571
118
        Message = "junk after doc element";
572
118
    }
573
87
    else if( XML_ERROR_PARAM_ENTITY_REF == xmlE ) {
574
0
        Message = "parameter entity reference";
575
0
    }
576
87
    else if( XML_ERROR_UNDEFINED_ENTITY == xmlE ) {
577
1
        Message = "undefined entity";
578
1
    }
579
86
    else if( XML_ERROR_RECURSIVE_ENTITY_REF == xmlE ) {
580
0
        Message = "recursive entity reference";
581
0
    }
582
86
    else if( XML_ERROR_ASYNC_ENTITY == xmlE ) {
583
0
        Message = "async entity";
584
0
    }
585
86
    else if( XML_ERROR_BAD_CHAR_REF == xmlE ) {
586
0
        Message = "bad char reference";
587
0
    }
588
86
    else if( XML_ERROR_BINARY_ENTITY_REF == xmlE ) {
589
0
        Message = "binary entity reference";
590
0
    }
591
86
    else if( XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF == xmlE ) {
592
0
        Message = "attribute external entity reference";
593
0
    }
594
86
    else if( XML_ERROR_MISPLACED_XML_PI == xmlE ) {
595
8
        Message = "misplaced xml processing instruction";
596
8
    }
597
78
    else if( XML_ERROR_UNKNOWN_ENCODING == xmlE ) {
598
1
        Message = "unknown encoding";
599
1
    }
600
77
    else if( XML_ERROR_INCORRECT_ENCODING == xmlE ) {
601
0
        Message = "incorrect encoding";
602
0
    }
603
77
    else if( XML_ERROR_UNCLOSED_CDATA_SECTION == xmlE ) {
604
56
        Message = "unclosed cdata section";
605
56
    }
606
21
    else if( XML_ERROR_EXTERNAL_ENTITY_HANDLING == xmlE ) {
607
0
        Message = "external entity reference";
608
0
    }
609
21
    else if( XML_ERROR_NOT_STANDALONE == xmlE ) {
610
0
        Message = "not standalone";
611
0
    }
612
613
12.5k
    OUString str = OUString::Concat("[") +
614
12.5k
        sSystemId +
615
12.5k
        " line " +
616
12.5k
        OUString::number( nLine ) +
617
12.5k
        "]: " +
618
12.5k
        Message +
619
12.5k
        "error";
620
621
12.5k
    return str;
622
12.5k
}
623
624
625
// starts parsing with actual parser !
626
void SaxExpatParser_Impl::parse( )
627
40.8k
{
628
40.8k
    const int nBufSize = 16*1024;
629
630
40.8k
    int nRead   = nBufSize;
631
40.8k
    css::uno::Sequence< sal_Int8 > seqOut(nBufSize);
632
633
78.8k
    while( nRead ) {
634
78.8k
        nRead = getEntity().converter.readAndConvert( seqOut , nBufSize );
635
636
78.8k
        bool bContinue(false);
637
638
78.8k
        if( ! nRead ) {
639
            // last call - must return OK
640
37.9k
            XML_Status const ret = XML_Parse( getEntity().pParser,
641
37.9k
                                   reinterpret_cast<const char *>(seqOut.getConstArray()),
642
37.9k
                                   0 ,
643
37.9k
                                   1 );
644
37.9k
            if (ret == XML_STATUS_OK) {
645
28.3k
                break;
646
28.3k
            }
647
40.8k
        } else {
648
40.8k
            bContinue = ( XML_Parse( getEntity().pParser,
649
40.8k
                                                reinterpret_cast<const char *>(seqOut.getConstArray()),
650
40.8k
                                                nRead,
651
40.8k
                                                0 ) != XML_STATUS_ERROR );
652
40.8k
        }
653
654
50.4k
        if( ! bContinue || bExceptionWasThrown ) {
655
656
12.5k
            if ( bRTExceptionWasThrown )
657
0
                throw rtexception;
658
659
            // Error during parsing !
660
12.5k
            XML_Error xmlE = XML_GetErrorCode( getEntity().pParser );
661
12.5k
            OUString sSystemId = rDocumentLocator->getSystemId();
662
12.5k
            sal_Int32 nLine = rDocumentLocator->getLineNumber();
663
664
12.5k
            SAXParseException aExcept(
665
12.5k
                getErrorMessage(xmlE , sSystemId, nLine) ,
666
12.5k
                css::uno::Reference< css::uno::XInterface >(),
667
12.5k
                css::uno::Any( &exception , cppu::UnoType<decltype(exception)>::get() ),
668
12.5k
                rDocumentLocator->getPublicId(),
669
12.5k
                rDocumentLocator->getSystemId(),
670
12.5k
                rDocumentLocator->getLineNumber(),
671
12.5k
                rDocumentLocator->getColumnNumber()
672
12.5k
                );
673
674
12.5k
            if( rErrorHandler.is() ) {
675
676
                // error handler is set, so the handler may throw the exception
677
0
                css::uno::Any a;
678
0
                a <<= aExcept;
679
0
                rErrorHandler->fatalError( a );
680
0
            }
681
682
            // Error handler has not thrown an exception, but parsing cannot go on,
683
            // so an exception MUST be thrown.
684
12.5k
            throw aExcept;
685
12.5k
        } // if( ! bContinue )
686
50.4k
    } // while
687
40.8k
}
688
689
690
// The C-Callbacks
691
692
693
void SaxExpatParser_Impl::callbackStartElement( void *pvThis ,
694
                                                const XML_Char *pwName ,
695
                                                const XML_Char **awAttributes )
696
306k
{
697
306k
    SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
698
699
306k
    if( !pImpl->rDocumentHandler.is() )
700
0
        return;
701
702
306k
    int i = 0;
703
306k
    pImpl->rAttrList->Clear();
704
705
916k
    while( awAttributes[i] ) {
706
609k
        assert(awAttributes[i+1]);
707
609k
        pImpl->rAttrList->AddAttribute(
708
609k
            XML_CHAR_TO_OUSTRING( awAttributes[i] ) ,
709
609k
            XML_CHAR_TO_OUSTRING( awAttributes[i+1] ) );
710
609k
        i +=2;
711
609k
    }
712
713
306k
    CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(
714
306k
        pImpl ,
715
306k
        rDocumentHandler->startElement( XML_CHAR_TO_OUSTRING( pwName ) ,
716
306k
                                        pImpl->rAttrList ) );
717
306k
}
718
719
void SaxExpatParser_Impl::callbackEndElement( void *pvThis , const XML_Char *pwName  )
720
290k
{
721
290k
    SaxExpatParser_Impl  *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
722
723
290k
    if( pImpl->rDocumentHandler.is() ) {
724
290k
        CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl,
725
290k
                rDocumentHandler->endElement( XML_CHAR_TO_OUSTRING( pwName ) ) );
726
290k
    }
727
290k
}
728
729
730
void SaxExpatParser_Impl::callbackCharacters( void *pvThis , const XML_Char *s , int nLen )
731
36.2k
{
732
36.2k
    SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
733
734
36.2k
    if( pImpl->rDocumentHandler.is() ) {
735
36.2k
        CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl ,
736
36.2k
                rDocumentHandler->characters( XML_CHAR_N_TO_USTRING(s,nLen) ) );
737
36.2k
    }
738
36.2k
}
739
740
void SaxExpatParser_Impl::callbackProcessingInstruction(    void *pvThis,
741
                                                    const XML_Char *sTarget ,
742
                                                    const XML_Char *sData )
743
945
{
744
945
    SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
745
945
    if( pImpl->rDocumentHandler.is() ) {
746
945
        CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(
747
945
                    pImpl ,
748
945
                    rDocumentHandler->processingInstruction( XML_CHAR_TO_OUSTRING( sTarget ),
749
945
                    XML_CHAR_TO_OUSTRING( sData ) ) );
750
945
    }
751
945
}
752
753
754
void SaxExpatParser_Impl::callbackEntityDecl(
755
    void *pvThis, const XML_Char *entityName,
756
    SAL_UNUSED_PARAMETER int /*is_parameter_entity*/,
757
    const XML_Char *value, SAL_UNUSED_PARAMETER int /*value_length*/,
758
    SAL_UNUSED_PARAMETER const XML_Char * /*base*/, const XML_Char *systemId,
759
    const XML_Char *publicId, const XML_Char *notationName)
760
2
{
761
2
    SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
762
2
    if (value) { // value != 0 means internal entity
763
2
        SAL_INFO("sax","SaxExpatParser: internal entity declaration, stopping");
764
2
        XML_StopParser(pImpl->getEntity().pParser, XML_FALSE);
765
2
        pImpl->exception = SAXParseException(
766
2
            u"SaxExpatParser: internal entity declaration, stopping"_ustr,
767
2
            nullptr, css::uno::Any(),
768
2
            pImpl->rDocumentLocator->getPublicId(),
769
2
            pImpl->rDocumentLocator->getSystemId(),
770
2
            pImpl->rDocumentLocator->getLineNumber(),
771
2
            pImpl->rDocumentLocator->getColumnNumber() );
772
2
        pImpl->bExceptionWasThrown = true;
773
2
    } else {
774
0
        if( pImpl->rDTDHandler.is() ) {
775
0
            CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(
776
0
                pImpl ,
777
0
                rDTDHandler->unparsedEntityDecl(
778
0
                    XML_CHAR_TO_OUSTRING( entityName ),
779
0
                    XML_CHAR_TO_OUSTRING( publicId ) ,
780
0
                    XML_CHAR_TO_OUSTRING( systemId ) ,
781
0
                    XML_CHAR_TO_OUSTRING( notationName ) ) );
782
0
        }
783
0
    }
784
2
}
785
786
void SaxExpatParser_Impl::callbackNotationDecl(
787
    void *pvThis, const XML_Char *notationName,
788
    SAL_UNUSED_PARAMETER const XML_Char * /*base*/, const XML_Char *systemId,
789
    const XML_Char *publicId)
790
0
{
791
0
    SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
792
0
    if( pImpl->rDTDHandler.is() ) {
793
0
        CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl,
794
0
                rDTDHandler->notationDecl(  XML_CHAR_TO_OUSTRING( notationName ) ,
795
0
                                            XML_CHAR_TO_OUSTRING( publicId ) ,
796
0
                                            XML_CHAR_TO_OUSTRING( systemId ) ) );
797
0
    }
798
799
0
}
800
801
802
bool SaxExpatParser_Impl::callbackExternalEntityRef(
803
    XML_Parser parser, const XML_Char *context,
804
    SAL_UNUSED_PARAMETER const XML_Char * /*base*/, const XML_Char *systemId,
805
    const XML_Char *publicId)
806
0
{
807
0
    bool bOK = true;
808
0
    SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(XML_GetUserData( parser ));
809
810
0
    struct Entity entity;
811
812
0
    if( pImpl->rEntityResolver.is() ) {
813
0
        try
814
0
        {
815
0
            entity.structSource = pImpl->rEntityResolver->resolveEntity(
816
0
                XML_CHAR_TO_OUSTRING( publicId ) ,
817
0
                XML_CHAR_TO_OUSTRING( systemId ) );
818
0
        }
819
0
        catch( const SAXParseException & e )
820
0
        {
821
0
            pImpl->exception = e;
822
0
            bOK = false;
823
0
        }
824
0
        catch( const SAXException & e )
825
0
        {
826
0
            pImpl->exception = SAXParseException(
827
0
                e.Message , e.Context , e.WrappedException ,
828
0
                pImpl->rDocumentLocator->getPublicId(),
829
0
                pImpl->rDocumentLocator->getSystemId(),
830
0
                pImpl->rDocumentLocator->getLineNumber(),
831
0
                pImpl->rDocumentLocator->getColumnNumber() );
832
0
            bOK = false;
833
0
        }
834
0
    }
835
836
0
    if( entity.structSource.aInputStream.is() ) {
837
0
        entity.pParser = XML_ExternalEntityParserCreate( parser , context, nullptr );
838
0
        if( ! entity.pParser )
839
0
        {
840
0
            return false;
841
0
        }
842
843
0
        entity.converter.setInputStream( entity.structSource.aInputStream );
844
0
        auto const xmlParser = entity.pParser;
845
0
        pImpl->pushEntity( std::move(entity) );
846
0
        try
847
0
        {
848
0
            pImpl->parse();
849
0
        }
850
0
        catch( const SAXParseException & e )
851
0
        {
852
0
            pImpl->exception = e;
853
0
            bOK = false;
854
0
        }
855
0
        catch( const IOException &e )
856
0
        {
857
0
            pImpl->exception.WrappedException <<= e;
858
0
            bOK = false;
859
0
        }
860
0
        catch( const css::uno::RuntimeException &e )
861
0
        {
862
0
            pImpl->exception.WrappedException <<=e;
863
0
            bOK = false;
864
0
        }
865
866
0
        pImpl->popEntity();
867
868
0
        XML_ParserFree( xmlParser );
869
0
    }
870
871
0
    return bOK;
872
0
}
873
874
int SaxExpatParser_Impl::callbackUnknownEncoding(
875
    SAL_UNUSED_PARAMETER void * /*encodingHandlerData*/,
876
    SAL_UNUSED_PARAMETER const XML_Char * /*name*/,
877
    SAL_UNUSED_PARAMETER XML_Encoding * /*info*/)
878
1
{
879
1
    return 0;
880
1
}
881
882
void SaxExpatParser_Impl::callbackDefault( void *pvThis,  const XML_Char *s,  int len)
883
0
{
884
0
    SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
885
886
0
    CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(  pImpl,
887
0
                rExtendedDocumentHandler->unknown( XML_CHAR_N_TO_USTRING( s ,len) ) );
888
0
}
889
890
void SaxExpatParser_Impl::callbackComment( void *pvThis , const XML_Char *s )
891
0
{
892
0
    SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
893
0
    CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl,
894
0
                rExtendedDocumentHandler->comment( XML_CHAR_TO_OUSTRING( s ) ) );
895
0
}
896
897
void SaxExpatParser_Impl::callbackStartCDATA( void *pvThis )
898
0
{
899
0
    SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
900
901
0
    CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl, rExtendedDocumentHandler->startCDATA() );
902
0
}
903
904
905
void SaxExpatParser_Impl::callErrorHandler( SaxExpatParser_Impl *pImpl ,
906
                                            const SAXParseException & e )
907
28
{
908
28
    try
909
28
    {
910
28
        if( pImpl->rErrorHandler.is() ) {
911
0
            css::uno::Any a;
912
0
            a <<= e;
913
0
            pImpl->rErrorHandler->error( a );
914
0
        }
915
28
        else {
916
28
            pImpl->exception = e;
917
28
            pImpl->bExceptionWasThrown = true;
918
28
        }
919
28
    }
920
28
    catch( const SAXParseException & ex ) {
921
0
        pImpl->exception = ex;
922
0
        pImpl->bExceptionWasThrown = true;
923
0
    }
924
28
    catch( const SAXException & ex ) {
925
0
        pImpl->exception = SAXParseException(
926
0
                                    ex.Message,
927
0
                                    ex.Context,
928
0
                                    ex.WrappedException,
929
0
                                    pImpl->rDocumentLocator->getPublicId(),
930
0
                                    pImpl->rDocumentLocator->getSystemId(),
931
0
                                    pImpl->rDocumentLocator->getLineNumber(),
932
0
                                    pImpl->rDocumentLocator->getColumnNumber()
933
0
                             );
934
0
        pImpl->bExceptionWasThrown = true;
935
0
    }
936
28
}
937
938
void SaxExpatParser_Impl::callbackEndCDATA( void *pvThis )
939
0
{
940
0
    SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
941
942
0
    CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(pImpl,rExtendedDocumentHandler->endCDATA() );
943
0
}
944
945
} // namespace
946
947
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
948
com_sun_star_comp_extensions_xml_sax_ParserExpat_get_implementation(
949
    css::uno::XComponentContext *,
950
    css::uno::Sequence<css::uno::Any> const &)
951
40.8k
{
952
40.8k
    return cppu::acquire(new SaxExpatParser);
953
40.8k
}
954
955
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */