LCOV - code coverage report
Current view: top level - sax/source/fastparser - fastparser.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 443 519 85.4 %
Date: 2015-06-13 12:38:46 Functions: 74 88 84.1 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "sax/fastparser.hxx"
      21             : #include "sax/fastattribs.hxx"
      22             : #include "xml2utf.hxx"
      23             : 
      24             : #include <com/sun/star/lang/DisposedException.hpp>
      25             : #include <com/sun/star/uno/XComponentContext.hpp>
      26             : #include <com/sun/star/xml/sax/FastToken.hpp>
      27             : #include <com/sun/star/xml/sax/SAXParseException.hpp>
      28             : #include <com/sun/star/xml/sax/XFastContextHandler.hpp>
      29             : #include <com/sun/star/xml/sax/XFastDocumentHandler.hpp>
      30             : #include <com/sun/star/xml/sax/XFastTokenHandler.hpp>
      31             : #include <cppuhelper/supportsservice.hxx>
      32             : #include <cppuhelper/exc_hlp.hxx>
      33             : #include <osl/conditn.hxx>
      34             : #include <osl/diagnose.h>
      35             : #include <rtl/ref.hxx>
      36             : #include <rtl/ustrbuf.hxx>
      37             : #include <sal/log.hxx>
      38             : #include <salhelper/thread.hxx>
      39             : 
      40             : #include <boost/optional.hpp>
      41             : #include <boost/scoped_ptr.hpp>
      42             : #include <boost/shared_ptr.hpp>
      43             : #include <stack>
      44             : #include <unordered_map>
      45             : #include <vector>
      46             : #include <queue>
      47             : #include <cassert>
      48             : #include <cstring>
      49             : #include <libxml/parser.h>
      50             : 
      51             : // Inverse of libxml's BAD_CAST.
      52             : #define XML_CAST( str ) reinterpret_cast< const sal_Char* >( str )
      53             : 
      54             : using namespace ::std;
      55             : using namespace ::osl;
      56             : using namespace ::cppu;
      57             : using namespace ::com::sun::star::uno;
      58             : using namespace ::com::sun::star::lang;
      59             : using namespace ::com::sun::star::xml::sax;
      60             : using namespace ::com::sun::star::io;
      61             : using namespace com::sun::star;
      62             : using namespace sax_fastparser;
      63             : 
      64             : namespace {
      65             : 
      66             : struct Event;
      67             : class FastLocatorImpl;
      68             : struct NamespaceDefine;
      69             : struct Entity;
      70             : 
      71             : typedef ::boost::shared_ptr< NamespaceDefine > NamespaceDefineRef;
      72             : 
      73             : typedef std::unordered_map< OUString, sal_Int32,
      74             :         OUStringHash, ::std::equal_to< OUString > > NamespaceMap;
      75             : 
      76             : typedef std::vector<Event> EventList;
      77             : 
      78             : enum CallbackType { INVALID, START_ELEMENT, END_ELEMENT, CHARACTERS, DONE, EXCEPTION };
      79             : 
      80     3717276 : struct Event
      81             : {
      82             :     CallbackType maType;
      83             :     sal_Int32 mnElementToken;
      84             :     OUString msNamespace;
      85             :     OUString msElementName;
      86             :     rtl::Reference< FastAttributeList > mxAttributes;
      87             :     OUString msChars;
      88             : };
      89             : 
      90     7296051 : struct NameWithToken
      91             : {
      92             :     OUString msName;
      93             :     sal_Int32 mnToken;
      94             : 
      95     2432017 :     NameWithToken(const OUString& sName, const sal_Int32& nToken) :
      96     2432017 :         msName(sName), mnToken(nToken) {}
      97             : };
      98             : 
      99     7296045 : struct SaxContext
     100             : {
     101             :     Reference< XFastContextHandler > mxContext;
     102             :     sal_Int32 mnElementToken;
     103             :     OUString  maNamespace;
     104             :     OUString  maElementName;
     105             : 
     106     2432018 :     SaxContext( sal_Int32 nElementToken, const OUString& aNamespace, const OUString& aElementName ):
     107     2432018 :             mnElementToken(nElementToken)
     108             :     {
     109     2432018 :         if (nElementToken == FastToken::DONTKNOW)
     110             :         {
     111        7443 :             maNamespace = aNamespace;
     112        7443 :             maElementName = aElementName;
     113             :         }
     114     2432018 :     }
     115             : };
     116             : 
     117             : 
     118       44638 : struct ParserData
     119             : {
     120             :     ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastDocumentHandler > mxDocumentHandler;
     121             :     ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler >    mxTokenHandler;
     122             :     FastTokenHandlerBase *mpTokenHandler;
     123             :     ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XErrorHandler >        mxErrorHandler;
     124             :     ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XEntityResolver >      mxEntityResolver;
     125             :     ::com::sun::star::lang::Locale          maLocale;
     126             : 
     127             :     ParserData();
     128             :     ~ParserData();
     129             : };
     130             : 
     131      106393 : struct NamespaceDefine
     132             : {
     133             :     OString     maPrefix;
     134             :     sal_Int32   mnToken;
     135             :     OUString    maNamespaceURL;
     136             : 
     137      106393 :     NamespaceDefine( const OString& rPrefix, sal_Int32 nToken, const OUString& rNamespaceURL ) : maPrefix( rPrefix ), mnToken( nToken ), maNamespaceURL( rNamespaceURL ) {}
     138             : };
     139             : 
     140             : // Entity binds all information needed for a single file | single call of parseStream
     141             : struct Entity : public ParserData
     142             : {
     143             :     // Amount of work producer sends to consumer in one iteration:
     144             :     static const size_t mnEventListSize = 1000;
     145             : 
     146             :     // unique for each Entity instance:
     147             : 
     148             :     // Number of valid events in mpProducedEvents:
     149             :     size_t mnProducedEventsSize;
     150             :     EventList *mpProducedEvents;
     151             :     std::queue< EventList * > maPendingEvents;
     152             :     std::queue< EventList * > maUsedEvents;
     153             :     osl::Mutex maEventProtector;
     154             : 
     155             :     static const size_t mnEventLowWater = 4;
     156             :     static const size_t mnEventHighWater = 8;
     157             :     osl::Condition maConsumeResume;
     158             :     osl::Condition maProduceResume;
     159             :     // Event we use to store data if threading is disabled:
     160             :     Event maSharedEvent;
     161             : 
     162             :     // copied in copy constructor:
     163             : 
     164             :     // Allow to disable threading for small documents:
     165             :     bool                                    mbEnableThreads;
     166             :     ::com::sun::star::xml::sax::InputSource maStructSource;
     167             :     xmlParserCtxtPtr                        mpParser;
     168             :     ::sax_expatwrap::XMLFile2UTFConverter   maConverter;
     169             : 
     170             :     // Exceptions cannot be thrown through the C-XmlParser (possible
     171             :     // resource leaks), therefore any exception thrown by a UNO callback
     172             :     // must be saved somewhere until the C-XmlParser is stopped.
     173             :     ::com::sun::star::uno::Any maSavedException;
     174             :     void saveException( const Any & e );
     175             :     void throwException( const ::rtl::Reference< FastLocatorImpl > &xDocumentLocator,
     176             :                          bool mbDuringParse );
     177             : 
     178             :     ::std::stack< NameWithToken >           maNamespaceStack;
     179             :     /* Context for main thread consuming events.
     180             :      * startElement() stores the data, which characters() and endElement() uses
     181             :      */
     182             :     ::std::stack< SaxContext>               maContextStack;
     183             :     // Determines which elements of maNamespaceDefines are valid in current context
     184             :     ::std::stack< sal_uInt32 >              maNamespaceCount;
     185             :     ::std::vector< NamespaceDefineRef >     maNamespaceDefines;
     186             : 
     187             :     explicit Entity( const ParserData& rData );
     188             :     Entity( const Entity& rEntity );
     189             :     ~Entity();
     190             :     void startElement( Event *pEvent );
     191             :     void characters( const OUString& sChars );
     192             :     void endElement();
     193             :     EventList* getEventList();
     194             :     Event& getEvent( CallbackType aType );
     195             : };
     196             : 
     197             : } // namespace
     198             : 
     199             : namespace sax_fastparser {
     200             : 
     201             : class FastSaxParserImpl
     202             : {
     203             : public:
     204             :     FastSaxParserImpl( FastSaxParser* pFront );
     205             :     ~FastSaxParserImpl();
     206             : 
     207             :     // XFastParser
     208             :     void parseStream( const ::com::sun::star::xml::sax::InputSource& aInputSource ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException, std::exception);
     209             :     void setFastDocumentHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastDocumentHandler >& Handler ) throw (::com::sun::star::uno::RuntimeException);
     210             :     void setTokenHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler >& Handler ) throw (::com::sun::star::uno::RuntimeException);
     211             :     void registerNamespace( const OUString& NamespaceURL, sal_Int32 NamespaceToken ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
     212             :     OUString getNamespaceURL( const OUString& rPrefix ) throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
     213             :     void setErrorHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XErrorHandler >& Handler ) throw (::com::sun::star::uno::RuntimeException);
     214             :     void setEntityResolver( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XEntityResolver >& Resolver ) throw (::com::sun::star::uno::RuntimeException);
     215             :     void setLocale( const ::com::sun::star::lang::Locale& rLocale ) throw (::com::sun::star::uno::RuntimeException);
     216             : 
     217             :     // called by the C callbacks of the expat parser
     218             :     void callbackStartElement( const xmlChar *localName , const xmlChar* prefix, const xmlChar* URI,
     219             :         int numNamespaces, const xmlChar** namespaces, int numAttributes, int defaultedAttributes, const xmlChar **attributes );
     220             :     void callbackEndElement( const xmlChar* localName, const xmlChar* prefix, const xmlChar* URI );
     221             :     void callbackCharacters( const xmlChar* s, int nLen );
     222             : #if 0
     223             :     bool callbackExternalEntityRef( XML_Parser parser, const xmlChar *openEntityNames, const xmlChar *base, const xmlChar *systemId, const xmlChar *publicId);
     224             :     void callbackEntityDecl(const xmlChar *entityName, int is_parameter_entity,
     225             :             const xmlChar *value, int value_length, const xmlChar *base,
     226             :             const xmlChar *systemId, const xmlChar *publicId,
     227             :             const xmlChar *notationName);
     228             : #endif
     229             : 
     230             :     void pushEntity( const Entity& rEntity );
     231             :     void popEntity();
     232    24936891 :     Entity& getEntity()             { return *mpTop; }
     233           0 :     const Entity& getEntity() const { return *mpTop; }
     234             :     void parse();
     235             :     void produce( bool bForceFlush = false );
     236             : 
     237             :     bool hasNamespaceURL( const OUString& rPrefix ) const;
     238             : 
     239             : private:
     240             :     bool consume(EventList *);
     241             :     void deleteUsedEvents();
     242             :     void sendPendingCharacters();
     243             : 
     244             :     sal_Int32 GetToken( const xmlChar* pName, sal_Int32 nameLen );
     245             :     sal_Int32 GetTokenWithPrefix( const xmlChar* pPrefix, int prefixLen, const xmlChar* pName, int nameLen ) throw (::com::sun::star::xml::sax::SAXException);
     246             :     OUString GetNamespaceURL( const OString& rPrefix ) throw (::com::sun::star::xml::sax::SAXException);
     247             :     sal_Int32 GetNamespaceToken( const OUString& rNamespaceURL );
     248             :     sal_Int32 GetTokenWithContextNamespace( sal_Int32 nNamespaceToken, const xmlChar* pName, int nNameLen );
     249             :     void DefineNamespace( const OString& rPrefix, const OUString& namespaceURL );
     250             : 
     251             : private:
     252             : #if 0
     253             :     FastSaxParser* mpFront;
     254             : #endif
     255             :     osl::Mutex maMutex; ///< Protecting whole parseStream() execution
     256             :     ::rtl::Reference< FastLocatorImpl >     mxDocumentLocator;
     257             :     NamespaceMap                            maNamespaceMap;
     258             : 
     259             :     ParserData maData;                      /// Cached parser configuration for next call of parseStream().
     260             : 
     261             :     Entity *mpTop;                          /// std::stack::top() is amazingly slow => cache this.
     262             :     ::std::stack< Entity > maEntities;      /// Entity stack for each call of parseStream().
     263             :     OUString pendingCharacters;             /// Data from characters() callback that needs to be sent.
     264             : };
     265             : 
     266             : } // namespace sax_fastparser
     267             : 
     268             : namespace {
     269             : 
     270        3136 : class ParserThread: public salhelper::Thread
     271             : {
     272             :     FastSaxParserImpl *mpParser;
     273             : public:
     274        1568 :     ParserThread(FastSaxParserImpl *pParser): Thread("Parser"), mpParser(pParser) {}
     275             : private:
     276        1568 :     virtual void execute() SAL_OVERRIDE
     277             :     {
     278             :         try
     279             :         {
     280        1568 :             mpParser->parse();
     281             :         }
     282           0 :         catch (const Exception &)
     283             :         {
     284           0 :             Entity &rEntity = mpParser->getEntity();
     285           0 :             rEntity.getEvent( EXCEPTION );
     286           0 :             mpParser->produce( true );
     287             :         }
     288        1568 :     }
     289             : };
     290             : 
     291             : extern "C" {
     292             : 
     293     2432018 : static void call_callbackStartElement(void *userData, const xmlChar *localName , const xmlChar* prefix, const xmlChar* URI,
     294             :     int numNamespaces, const xmlChar** namespaces, int numAttributes, int defaultedAttributes, const xmlChar **attributes)
     295             : {
     296     2432018 :     FastSaxParserImpl* pFastParser = static_cast<FastSaxParserImpl*>( userData );
     297     2432018 :     pFastParser->callbackStartElement( localName, prefix, URI, numNamespaces, namespaces, numAttributes, defaultedAttributes, attributes );
     298     2432018 : }
     299             : 
     300     2432011 : static void call_callbackEndElement(void *userData, const xmlChar* localName, const xmlChar* prefix, const xmlChar* URI)
     301             : {
     302     2432011 :     FastSaxParserImpl* pFastParser = static_cast<FastSaxParserImpl*>( userData );
     303     2432011 :     pFastParser->callbackEndElement( localName, prefix, URI );
     304     2432011 : }
     305             : 
     306      179028 : static void call_callbackCharacters( void *userData , const xmlChar *s , int nLen )
     307             : {
     308      179028 :     FastSaxParserImpl* pFastParser = static_cast<FastSaxParserImpl*>( userData );
     309      179028 :     pFastParser->callbackCharacters( s, nLen );
     310      179028 : }
     311             : 
     312             : #if 0
     313             : static void call_callbackEntityDecl(void *userData, const xmlChar *entityName,
     314             :         int is_parameter_entity, const xmlChar *value, int value_length,
     315             :         const xmlChar *base, const xmlChar *systemId,
     316             :         const xmlChar *publicId, const xmlChar *notationName)
     317             : {
     318             :     FastSaxParserImpl* pFastParser = reinterpret_cast<FastSaxParserImpl*>(userData);
     319             :     pFastParser->callbackEntityDecl(entityName, is_parameter_entity, value,
     320             :             value_length, base, systemId, publicId, notationName);
     321             : }
     322             : 
     323             : static int call_callbackExternalEntityRef( XML_Parser parser,
     324             :         const xmlChar *openEntityNames, const xmlChar *base, const xmlChar *systemId, const xmlChar *publicId )
     325             : {
     326             :     FastSaxParserImpl* pFastParser = reinterpret_cast<FastSaxParserImpl*>( XML_GetUserData( parser ) );
     327             :     return pFastParser->callbackExternalEntityRef( parser, openEntityNames, base, systemId, publicId );
     328             : }
     329             : #endif
     330             : }
     331             : 
     332       60010 : class FastLocatorImpl : public WeakImplHelper1< XLocator >
     333             : {
     334             : public:
     335       30005 :     FastLocatorImpl( FastSaxParserImpl *p ) : mpParser(p) {}
     336             : 
     337       30005 :     void dispose() { mpParser = 0; }
     338          12 :     void checkDispose() throw (RuntimeException) { if( !mpParser ) throw DisposedException(); }
     339             : 
     340             :     //XLocator
     341             :     virtual sal_Int32 SAL_CALL getColumnNumber() throw (RuntimeException, std::exception) SAL_OVERRIDE;
     342             :     virtual sal_Int32 SAL_CALL getLineNumber() throw (RuntimeException, std::exception) SAL_OVERRIDE;
     343             :     virtual OUString SAL_CALL getPublicId() throw (RuntimeException, std::exception) SAL_OVERRIDE;
     344             :     virtual OUString SAL_CALL getSystemId() throw (RuntimeException, std::exception) SAL_OVERRIDE;
     345             : 
     346             : private:
     347             :     FastSaxParserImpl *mpParser;
     348             : };
     349             : 
     350           2 : sal_Int32 SAL_CALL FastLocatorImpl::getColumnNumber() throw (RuntimeException, std::exception)
     351             : {
     352           2 :     checkDispose();
     353           2 :     return xmlSAX2GetColumnNumber( mpParser->getEntity().mpParser );
     354             : }
     355             : 
     356           4 : sal_Int32 SAL_CALL FastLocatorImpl::getLineNumber() throw (RuntimeException, std::exception)
     357             : {
     358           4 :     checkDispose();
     359           4 :     return xmlSAX2GetLineNumber( mpParser->getEntity().mpParser );
     360             : }
     361             : 
     362           2 : OUString SAL_CALL FastLocatorImpl::getPublicId() throw (RuntimeException, std::exception)
     363             : {
     364           2 :     checkDispose();
     365           2 :     return mpParser->getEntity().maStructSource.sPublicId;
     366             : }
     367             : 
     368           4 : OUString SAL_CALL FastLocatorImpl::getSystemId() throw (RuntimeException, std::exception)
     369             : {
     370           4 :     checkDispose();
     371           4 :     return mpParser->getEntity().maStructSource.sSystemId;
     372             : }
     373             : 
     374       30005 : ParserData::ParserData()
     375       30005 :     : mpTokenHandler( NULL )
     376       30005 : {}
     377             : 
     378       74643 : ParserData::~ParserData()
     379       74643 : {}
     380             : 
     381       22427 : Entity::Entity(const ParserData& rData)
     382             :     : ParserData(rData)
     383             :     , mnProducedEventsSize(0)
     384             :     , mpProducedEvents(NULL)
     385             :     , mbEnableThreads(false)
     386       22427 :     , mpParser(NULL)
     387             : {
     388       22427 : }
     389             : 
     390       22211 : Entity::Entity(const Entity& e)
     391             :     : ParserData(e)
     392             :     , mnProducedEventsSize(0)
     393             :     , mpProducedEvents(NULL)
     394             :     , mbEnableThreads(e.mbEnableThreads)
     395             :     , maStructSource(e.maStructSource)
     396             :     , mpParser(e.mpParser)
     397             :     , maConverter(e.maConverter)
     398             :     , maSavedException(e.maSavedException)
     399             :     , maNamespaceStack(e.maNamespaceStack)
     400             :     , maContextStack(e.maContextStack)
     401             :     , maNamespaceCount(e.maNamespaceCount)
     402       22211 :     , maNamespaceDefines(e.maNamespaceDefines)
     403             : {
     404       22211 : }
     405             : 
     406       44638 : Entity::~Entity()
     407             : {
     408       44638 : }
     409             : 
     410     2432015 : void Entity::startElement( Event *pEvent )
     411             : {
     412     2432015 :     const sal_Int32& nElementToken = pEvent->mnElementToken;
     413     2432015 :     const OUString& aNamespace = pEvent->msNamespace;
     414     2432015 :     const OUString& aElementName = pEvent->msElementName;
     415             : 
     416             :     // Use un-wrapped pointers to avoid significant acquire/release overhead
     417     2432015 :     XFastContextHandler *pParentContext = NULL;
     418     2432015 :     if( !maContextStack.empty() )
     419             :     {
     420     2409806 :         pParentContext = maContextStack.top().mxContext.get();
     421     2409807 :         if( !pParentContext )
     422             :         {
     423       83657 :             maContextStack.push( SaxContext(nElementToken, aNamespace, aElementName) );
     424     2515675 :             return;
     425             :         }
     426             :     }
     427             : 
     428     2348361 :     maContextStack.push( SaxContext( nElementToken, aNamespace, aElementName ) );
     429             : 
     430             :     try
     431             :     {
     432     2348358 :         Reference< XFastAttributeList > xAttr( pEvent->mxAttributes.get() );
     433     4696722 :         Reference< XFastContextHandler > xContext;
     434     2348361 :         if( nElementToken == FastToken::DONTKNOW )
     435             :         {
     436        6452 :             if( pParentContext )
     437        5953 :                 xContext = pParentContext->createUnknownChildContext( aNamespace, aElementName, xAttr );
     438         499 :             else if( mxDocumentHandler.is() )
     439         497 :                 xContext = mxDocumentHandler->createUnknownChildContext( aNamespace, aElementName, xAttr );
     440             : 
     441        6452 :             if( xContext.is() )
     442             :             {
     443        6136 :                 xContext->startUnknownElement( aNamespace, aElementName, xAttr );
     444             :             }
     445             :         }
     446             :         else
     447             :         {
     448     2341909 :             if( pParentContext )
     449     2320197 :                 xContext = pParentContext->createFastChildContext( nElementToken, xAttr );
     450       21712 :             else if( mxDocumentHandler.is() )
     451       21712 :                 xContext = mxDocumentHandler->createFastChildContext( nElementToken, xAttr );
     452             : 
     453     2341907 :             if( xContext.is() )
     454     2268221 :                 xContext->startFastElement( nElementToken, xAttr );
     455             :         }
     456             :         // swap the reference we own in to avoid referencing thrash.
     457     2348360 :         maContextStack.top().mxContext.set( static_cast<XFastContextHandler *>( xContext.get() ) );
     458     4696720 :         xContext.set( NULL, UNO_REF_NO_ACQUIRE );
     459             :     }
     460           1 :     catch (const Exception&)
     461             :     {
     462           1 :         saveException( ::cppu::getCaughtException() );
     463             :     }
     464             : }
     465             : 
     466      173437 : void Entity::characters( const OUString& sChars )
     467             : {
     468      173437 :     if (maContextStack.empty())
     469             :     {
     470             :         // Malformed XML stream !?
     471      173437 :         return;
     472             :     }
     473             : 
     474      173437 :     const Reference< XFastContextHandler >& xContext( maContextStack.top().mxContext );
     475      173437 :     if( xContext.is() ) try
     476             :     {
     477      168427 :         xContext->characters( sChars );
     478             :     }
     479           0 :     catch (const Exception&)
     480             :     {
     481           0 :         saveException( ::cppu::getCaughtException() );
     482             :     }
     483             : }
     484             : 
     485     2432010 : void Entity::endElement()
     486             : {
     487     2432010 :     if (maContextStack.empty())
     488             :     {
     489             :         // Malformed XML stream !?
     490     2432011 :         return;
     491             :     }
     492             : 
     493     2432009 :     const SaxContext& aContext = maContextStack.top();
     494     2432011 :     const Reference< XFastContextHandler >& xContext( aContext.mxContext );
     495     2432011 :     if( xContext.is() ) try
     496             :     {
     497     2274349 :         sal_Int32 nElementToken = aContext.mnElementToken;
     498     2274349 :         if( nElementToken != FastToken::DONTKNOW )
     499     2268213 :             xContext->endFastElement( nElementToken );
     500             :         else
     501        6136 :             xContext->endUnknownElement( aContext.maNamespace, aContext.maElementName );
     502             :     }
     503           0 :     catch (const Exception&)
     504             :     {
     505           0 :         saveException( ::cppu::getCaughtException() );
     506             :     }
     507     2432008 :     maContextStack.pop();
     508             : }
     509             : 
     510     1150196 : EventList* Entity::getEventList()
     511             : {
     512     1150196 :     if (!mpProducedEvents)
     513             :     {
     514        1904 :         osl::ResettableMutexGuard aGuard(maEventProtector);
     515        1904 :         if (!maUsedEvents.empty())
     516             :         {
     517          90 :             mpProducedEvents = maUsedEvents.front();
     518          90 :             maUsedEvents.pop();
     519          90 :             aGuard.clear(); // unlock
     520          90 :             mnProducedEventsSize = 0;
     521             :         }
     522        1904 :         if (!mpProducedEvents)
     523             :         {
     524        1814 :             mpProducedEvents = new EventList();
     525        1814 :             mpProducedEvents->resize(mnEventListSize);
     526        1814 :             mnProducedEventsSize = 0;
     527        1904 :         }
     528             :     }
     529     1150196 :     return mpProducedEvents;
     530             : }
     531             : 
     532     5059675 : Event& Entity::getEvent( CallbackType aType )
     533             : {
     534     5059675 :     if (!mbEnableThreads)
     535     3909479 :         return maSharedEvent;
     536             : 
     537     1150196 :     EventList* pEventList = getEventList();
     538     1150196 :     Event& rEvent = (*pEventList)[mnProducedEventsSize++];
     539     1150196 :     rEvent.maType = aType;
     540     1150196 :     return rEvent;
     541             : }
     542             : 
     543           2 : OUString lclGetErrorMessage( xmlParserCtxtPtr ctxt, const OUString& sSystemId, sal_Int32 nLine )
     544             : {
     545             :     const sal_Char* pMessage;
     546           2 :     xmlErrorPtr error = xmlCtxtGetLastError( ctxt );
     547           2 :     if( error && error->message )
     548           2 :         pMessage = error->message;
     549             :     else
     550           0 :         pMessage = "unknown error";
     551           2 :     OUStringBuffer aBuffer( "[" );
     552           2 :     aBuffer.append( sSystemId );
     553           2 :     aBuffer.append( " line " );
     554           2 :     aBuffer.append( nLine );
     555           2 :     aBuffer.append( "]: " );
     556           2 :     aBuffer.appendAscii( pMessage );
     557           2 :     return aBuffer.makeStringAndClear();
     558             : }
     559             : 
     560             : // throw an exception, but avoid callback if
     561             : // during a threaded produce
     562           2 : void Entity::throwException( const ::rtl::Reference< FastLocatorImpl > &xDocumentLocator,
     563             :                              bool mbDuringParse )
     564             : {
     565             :     // Error during parsing !
     566             :     SAXParseException aExcept(
     567             :         lclGetErrorMessage( mpParser,
     568           2 :                             xDocumentLocator->getSystemId(),
     569           2 :                             xDocumentLocator->getLineNumber() ),
     570             :         Reference< XInterface >(),
     571           2 :         Any( &maSavedException, cppu::UnoType<decltype(maSavedException)>::get() ),
     572           2 :         xDocumentLocator->getPublicId(),
     573           2 :         xDocumentLocator->getSystemId(),
     574           2 :         xDocumentLocator->getLineNumber(),
     575           2 :         xDocumentLocator->getColumnNumber()
     576          14 :     );
     577             : 
     578             :     // error handler is set, it may throw the exception
     579           2 :     if( !mbDuringParse || !mbEnableThreads )
     580             :     {
     581           2 :         if (mxErrorHandler.is() )
     582           0 :             mxErrorHandler->fatalError( Any( aExcept ) );
     583             :     }
     584             : 
     585             :     // error handler has not thrown, but parsing must stop => throw ourselves
     586           2 :     throw aExcept;
     587             : }
     588             : 
     589             : // In the single threaded case we emit events via our C
     590             : // callbacks, so any exception caught must be queued up until
     591             : // we can safely re-throw it from our C++ parent of parse()
     592             : 
     593             : // If multi-threaded, we need to push an EXCEPTION event, at
     594             : // which point we transfer ownership of maSavedException to
     595             : // the consuming thread.
     596           1 : void Entity::saveException( const Any & e )
     597             : {
     598             :     // fdo#81214 - allow the parser to run on after an exception,
     599             :     // unexpectedly some 'startElements' produce an UNO_QUERY_THROW
     600             :     // for XComponent; and yet expect to continue parsing.
     601             :     SAL_WARN("sax", "Unexpected exception from XML parser "
     602             :             << e.get<Exception>().Message);
     603           1 :     maSavedException = e;
     604           1 : }
     605             : 
     606             : } // namespace
     607             : 
     608             : namespace sax_fastparser {
     609             : 
     610       30005 : FastSaxParserImpl::FastSaxParserImpl( FastSaxParser* ) :
     611             : #if 0
     612             :     mpFront(pFront),
     613             : #endif
     614       30005 :     mpTop(NULL)
     615             : {
     616       30005 :     mxDocumentLocator.set( new FastLocatorImpl( this ) );
     617       30005 : }
     618             : 
     619       60010 : FastSaxParserImpl::~FastSaxParserImpl()
     620             : {
     621       30005 :     if( mxDocumentLocator.is() )
     622       30005 :         mxDocumentLocator->dispose();
     623       30005 : }
     624             : 
     625      106393 : void FastSaxParserImpl::DefineNamespace( const OString& rPrefix, const OUString& namespaceURL )
     626             : {
     627      106393 :     Entity& rEntity = getEntity();
     628             :     assert(!rEntity.maNamespaceCount.empty()); // need a context!
     629             : 
     630      106393 :     sal_uInt32 nOffset = rEntity.maNamespaceCount.top()++;
     631      106393 :     if( rEntity.maNamespaceDefines.size() <= nOffset )
     632       22211 :         rEntity.maNamespaceDefines.resize( rEntity.maNamespaceDefines.size() + 64 );
     633             : 
     634      106393 :     rEntity.maNamespaceDefines[nOffset].reset( new NamespaceDefine( rPrefix, GetNamespaceToken( namespaceURL ), namespaceURL ) );
     635      106393 : }
     636             : 
     637     5687878 : sal_Int32 FastSaxParserImpl::GetToken( const xmlChar* pName, sal_Int32 nameLen /* = 0 */ )
     638             : {
     639     5687877 :     return FastTokenHandlerBase::getTokenFromChars( getEntity().mxTokenHandler,
     640     5687878 :                                                     getEntity().mpTokenHandler,
     641    17063632 :                                                     XML_CAST( pName ), nameLen ); // uses utf-8
     642             : }
     643             : 
     644     4787166 : sal_Int32 FastSaxParserImpl::GetTokenWithPrefix( const xmlChar* pPrefix, int nPrefixLen, const xmlChar* pName, int nNameLen ) throw (SAXException)
     645             : {
     646     4787166 :     sal_Int32 nNamespaceToken = FastToken::DONTKNOW;
     647             : 
     648     4787166 :     Entity& rEntity = getEntity();
     649     4787166 :     if (rEntity.maNamespaceCount.empty())
     650           0 :         return nNamespaceToken;
     651             : 
     652     4787166 :     sal_uInt32 nNamespace = rEntity.maNamespaceCount.top();
     653    21733218 :     while( nNamespace-- )
     654             :     {
     655    16946052 :         const OString& rPrefix( rEntity.maNamespaceDefines[nNamespace]->maPrefix );
     656    22353262 :         if( (rPrefix.getLength() == nPrefixLen) &&
     657     5407210 :             (strncmp( rPrefix.getStr(), XML_CAST( pPrefix ), nPrefixLen ) == 0 ) )
     658             :         {
     659     4787166 :             nNamespaceToken = rEntity.maNamespaceDefines[nNamespace]->mnToken;
     660     4787166 :             break;
     661             :         }
     662             : 
     663    12158886 :         if( !nNamespace )
     664           0 :             throw SAXException("No namespace defined for " + OUString(XML_CAST(pPrefix),
     665           0 :                     nPrefixLen, RTL_TEXTENCODING_UTF8), Reference< XInterface >(), Any());
     666             :     }
     667             : 
     668     4787166 :     if( nNamespaceToken != FastToken::DONTKNOW )
     669             :     {
     670     4777119 :         sal_Int32 nNameToken = GetToken( pName, nNameLen );
     671     4777119 :         if( nNameToken != FastToken::DONTKNOW )
     672     4762821 :             return nNamespaceToken | nNameToken;
     673             :     }
     674             : 
     675       24345 :     return FastToken::DONTKNOW;
     676             : }
     677             : 
     678     1489940 : sal_Int32 FastSaxParserImpl::GetNamespaceToken( const OUString& rNamespaceURL )
     679             : {
     680     1489940 :     NamespaceMap::iterator aIter( maNamespaceMap.find( rNamespaceURL ) );
     681     1489940 :     if( aIter != maNamespaceMap.end() )
     682       96316 :         return (*aIter).second;
     683             :     else
     684     1393624 :         return FastToken::DONTKNOW;
     685             : }
     686             : 
     687           0 : OUString FastSaxParserImpl::GetNamespaceURL( const OString& rPrefix ) throw (SAXException)
     688             : {
     689           0 :     Entity& rEntity = getEntity();
     690           0 :     if( !rEntity.maNamespaceCount.empty() )
     691             :     {
     692           0 :         sal_uInt32 nNamespace = rEntity.maNamespaceCount.top();
     693           0 :         while( nNamespace-- )
     694           0 :             if( rEntity.maNamespaceDefines[nNamespace]->maPrefix == rPrefix )
     695           0 :                 return rEntity.maNamespaceDefines[nNamespace]->maNamespaceURL;
     696             :     }
     697             : 
     698           0 :     throw SAXException("No namespace defined for " + OUString::fromUtf8(rPrefix),
     699           0 :             Reference< XInterface >(), Any());
     700             : }
     701             : 
     702      109353 : sal_Int32 FastSaxParserImpl::GetTokenWithContextNamespace( sal_Int32 nNamespaceToken, const xmlChar* pName, int nNameLen )
     703             : {
     704      109353 :     if( nNamespaceToken != FastToken::DONTKNOW )
     705             :     {
     706      107547 :         sal_Int32 nNameToken = GetToken( pName, nNameLen );
     707      107547 :         if( nNameToken != FastToken::DONTKNOW )
     708      107546 :             return nNamespaceToken | nNameToken;
     709             :     }
     710             : 
     711        1807 :     return FastToken::DONTKNOW;
     712             : }
     713             : 
     714             : /***************
     715             : *
     716             : * parseStream does Parser-startup initializations. The FastSaxParser::parse() method does
     717             : * the file-specific initialization work. (During a parser run, external files may be opened)
     718             : *
     719             : ****************/
     720       22427 : void FastSaxParserImpl::parseStream(const InputSource& maStructSource)
     721             :     throw (SAXException, IOException, RuntimeException, std::exception)
     722             : {
     723       22427 :     xmlInitParser();
     724             : 
     725             :     // Only one text at one time
     726       22427 :     MutexGuard guard( maMutex );
     727             : 
     728       44854 :     Entity entity( maData );
     729       22427 :     entity.maStructSource = maStructSource;
     730             : 
     731       22427 :     if( !entity.mxTokenHandler.is() )
     732           0 :         throw SAXException("No token handler, use setTokenHandler()", Reference< XInterface >(), Any() );
     733             : 
     734       22427 :     if( !entity.maStructSource.aInputStream.is() )
     735         216 :         throw SAXException("No input source", Reference< XInterface >(), Any() );
     736             : 
     737       22211 :     entity.maConverter.setInputStream( entity.maStructSource.aInputStream );
     738       22211 :     if( !entity.maStructSource.sEncoding.isEmpty() )
     739           0 :         entity.maConverter.setEncoding( OUStringToOString( entity.maStructSource.sEncoding, RTL_TEXTENCODING_ASCII_US ) );
     740             : 
     741       22211 :     pushEntity( entity );
     742       22211 :     Entity& rEntity = getEntity();
     743             :     try
     744             :     {
     745             :         // start the document
     746       22211 :         if( rEntity.mxDocumentHandler.is() )
     747             :         {
     748       22209 :             Reference< XLocator > xLoc( mxDocumentLocator.get() );
     749       22209 :             rEntity.mxDocumentHandler->setDocumentLocator( xLoc );
     750       22209 :             rEntity.mxDocumentHandler->startDocument();
     751             :         }
     752             : 
     753       22211 :         rEntity.mbEnableThreads = (rEntity.maStructSource.aInputStream->available() > 10000);
     754             : 
     755       22211 :         if (rEntity.mbEnableThreads)
     756             :         {
     757        1568 :             rtl::Reference<ParserThread> xParser;
     758        1568 :             xParser = new ParserThread(this);
     759        1568 :             xParser->launch();
     760        1568 :             bool done = false;
     761        1647 :             do {
     762        1647 :                 rEntity.maConsumeResume.wait();
     763        1647 :                 rEntity.maConsumeResume.reset();
     764             : 
     765        1647 :                 osl::ResettableMutexGuard aGuard(rEntity.maEventProtector);
     766        5198 :                 while (!rEntity.maPendingEvents.empty())
     767             :                 {
     768        1904 :                     if (rEntity.maPendingEvents.size() <= rEntity.mnEventLowWater)
     769        1883 :                         rEntity.maProduceResume.set(); // start producer again
     770             : 
     771        1904 :                     EventList *pEventList = rEntity.maPendingEvents.front();
     772        1904 :                     rEntity.maPendingEvents.pop();
     773        1904 :                     aGuard.clear(); // unlock
     774             : 
     775        1904 :                     if (!consume(pEventList))
     776        1568 :                         done = true;
     777             : 
     778        1904 :                     aGuard.reset(); // lock
     779        1904 :                     rEntity.maUsedEvents.push(pEventList);
     780        1647 :                 }
     781        1647 :             } while (!done);
     782        1568 :             xParser->join();
     783        1568 :             deleteUsedEvents();
     784             :         }
     785             :         else
     786             :         {
     787       20643 :             parse();
     788             :         }
     789             : 
     790             :         // finish document
     791       22209 :         if( rEntity.mxDocumentHandler.is() )
     792             :         {
     793       22208 :             rEntity.mxDocumentHandler->endDocument();
     794             :         }
     795             :     }
     796           4 :     catch (const SAXException&)
     797             :     {
     798             :         // TODO free mpParser.myDoc ?
     799           2 :         xmlFreeParserCtxt( rEntity.mpParser );
     800           2 :         popEntity();
     801           2 :         throw;
     802             :     }
     803           0 :     catch (const IOException&)
     804             :     {
     805           0 :         xmlFreeParserCtxt( rEntity.mpParser );
     806           0 :         popEntity();
     807           0 :         throw;
     808             :     }
     809           0 :     catch (const RuntimeException&)
     810             :     {
     811           0 :         xmlFreeParserCtxt( rEntity.mpParser );
     812           0 :         popEntity();
     813           0 :         throw;
     814             :     }
     815             : 
     816       22209 :     xmlFreeParserCtxt( rEntity.mpParser );
     817       44636 :     popEntity();
     818       22209 : }
     819             : 
     820       28567 : void FastSaxParserImpl::setFastDocumentHandler( const Reference< XFastDocumentHandler >& Handler ) throw (RuntimeException)
     821             : {
     822       28567 :     maData.mxDocumentHandler = Handler;
     823       28567 : }
     824             : 
     825       30003 : void FastSaxParserImpl::setTokenHandler( const Reference< XFastTokenHandler >& xHandler ) throw (RuntimeException)
     826             : {
     827       30003 :     maData.mxTokenHandler = xHandler;
     828       30003 :     maData.mpTokenHandler = dynamic_cast< FastTokenHandlerBase *>( xHandler.get() );
     829       30003 : }
     830             : 
     831     1368704 : void FastSaxParserImpl::registerNamespace( const OUString& NamespaceURL, sal_Int32 NamespaceToken ) throw (IllegalArgumentException, RuntimeException)
     832             : {
     833     1368704 :     if( NamespaceToken >= FastToken::NAMESPACE )
     834             :     {
     835     1368704 :         if( GetNamespaceToken( NamespaceURL ) == FastToken::DONTKNOW )
     836             :         {
     837     1368704 :             maNamespaceMap[ NamespaceURL ] = NamespaceToken;
     838     2737408 :             return;
     839             :         }
     840             :     }
     841           0 :     throw IllegalArgumentException();
     842             : }
     843             : 
     844           0 : OUString FastSaxParserImpl::getNamespaceURL( const OUString& rPrefix ) throw(IllegalArgumentException, RuntimeException)
     845             : {
     846             :     try
     847             :     {
     848           0 :         return GetNamespaceURL( OUStringToOString( rPrefix, RTL_TEXTENCODING_UTF8 ) );
     849             :     }
     850           0 :     catch (const Exception&)
     851             :     {
     852             :     }
     853           0 :     throw IllegalArgumentException();
     854             : }
     855             : 
     856           0 : void FastSaxParserImpl::setErrorHandler(const Reference< XErrorHandler > & Handler) throw (RuntimeException)
     857             : {
     858           0 :     maData.mxErrorHandler = Handler;
     859           0 : }
     860             : 
     861           0 : void FastSaxParserImpl::setEntityResolver(const Reference < XEntityResolver > & Resolver) throw (RuntimeException)
     862             : {
     863           0 :     maData.mxEntityResolver = Resolver;
     864           0 : }
     865             : 
     866           0 : void FastSaxParserImpl::setLocale( const lang::Locale & Locale ) throw (RuntimeException)
     867             : {
     868           0 :     maData.maLocale = Locale;
     869           0 : }
     870             : 
     871        1568 : void FastSaxParserImpl::deleteUsedEvents()
     872             : {
     873        1568 :     Entity& rEntity = getEntity();
     874        1568 :     osl::ResettableMutexGuard aGuard(rEntity.maEventProtector);
     875             : 
     876        4950 :     while (!rEntity.maUsedEvents.empty())
     877             :     {
     878        1814 :         EventList *pEventList = rEntity.maUsedEvents.front();
     879        1814 :         rEntity.maUsedEvents.pop();
     880             : 
     881        1814 :         aGuard.clear(); // unlock
     882             : 
     883        1814 :         delete pEventList;
     884             : 
     885        1814 :         aGuard.reset(); // lock
     886        1568 :     }
     887        1568 : }
     888             : 
     889     1150196 : void FastSaxParserImpl::produce( bool bForceFlush )
     890             : {
     891     1150196 :     Entity& rEntity = getEntity();
     892     2298824 :     if (bForceFlush ||
     893     1148628 :         rEntity.mnProducedEventsSize == rEntity.mnEventListSize)
     894             :     {
     895        1904 :         osl::ResettableMutexGuard aGuard(rEntity.maEventProtector);
     896             : 
     897        3813 :         while (rEntity.maPendingEvents.size() >= rEntity.mnEventHighWater)
     898             :         { // pause parsing for a bit
     899           5 :             aGuard.clear(); // unlock
     900           5 :             rEntity.maProduceResume.wait();
     901           5 :             rEntity.maProduceResume.reset();
     902           5 :             aGuard.reset(); // lock
     903             :         }
     904             : 
     905        1904 :         rEntity.maPendingEvents.push(rEntity.mpProducedEvents);
     906        1904 :         rEntity.mpProducedEvents = 0;
     907             : 
     908        1904 :         aGuard.clear(); // unlock
     909             : 
     910        1904 :         rEntity.maConsumeResume.set();
     911             :     }
     912     1150196 : }
     913             : 
     914         129 : bool FastSaxParserImpl::hasNamespaceURL( const OUString& rPrefix ) const
     915             : {
     916         129 :     if (maEntities.empty())
     917         129 :         return false;
     918             : 
     919           0 :     const Entity& rEntity = getEntity();
     920             : 
     921           0 :     if (rEntity.maNamespaceCount.empty())
     922           0 :         return false;
     923             : 
     924           0 :     OString aPrefix = OUStringToOString(rPrefix, RTL_TEXTENCODING_UTF8);
     925           0 :     sal_uInt32 nNamespace = rEntity.maNamespaceCount.top();
     926           0 :     while (nNamespace--)
     927             :     {
     928           0 :         if (rEntity.maNamespaceDefines[nNamespace]->maPrefix == aPrefix)
     929           0 :             return true;
     930             :     }
     931             : 
     932           0 :     return false;
     933             : }
     934             : 
     935        1904 : bool FastSaxParserImpl::consume(EventList *pEventList)
     936             : {
     937        1904 :     Entity& rEntity = getEntity();
     938     3451568 :     for (EventList::iterator aEventIt = pEventList->begin();
     939     2301047 :          aEventIt != pEventList->end(); ++aEventIt)
     940             :     {
     941     1150184 :         switch ((*aEventIt).maType)
     942             :         {
     943             :             case START_ELEMENT:
     944      555728 :                 rEntity.startElement( &(*aEventIt) );
     945      555731 :                 break;
     946             :             case END_ELEMENT:
     947      555730 :                 rEntity.endElement();
     948      555731 :                 break;
     949             :             case CHARACTERS:
     950       37165 :                 rEntity.characters( (*aEventIt).msChars );
     951       37166 :                 break;
     952             :             case DONE:
     953        3136 :                 return false;
     954             :             case EXCEPTION:
     955           0 :                 rEntity.throwException( mxDocumentLocator, false );
     956           0 :                 return false;
     957             :             default:
     958             :                 assert(false);
     959           0 :                 return false;
     960             :         }
     961             :     }
     962         336 :     return true;
     963             : }
     964             : 
     965       22211 : void FastSaxParserImpl::pushEntity( const Entity& rEntity )
     966             : {
     967       22211 :     maEntities.push( rEntity );
     968       22211 :     mpTop = &maEntities.top();
     969       22211 : }
     970             : 
     971       22211 : void FastSaxParserImpl::popEntity()
     972             : {
     973       22211 :     maEntities.pop();
     974       22211 :     mpTop = !maEntities.empty() ? &maEntities.top() : NULL;
     975       22211 : }
     976             : 
     977             : // starts parsing with actual parser !
     978       22211 : void FastSaxParserImpl::parse()
     979             : {
     980       22211 :     const int BUFFER_SIZE = 16 * 1024;
     981       22211 :     Sequence< sal_Int8 > seqOut( BUFFER_SIZE );
     982             : 
     983       22211 :     Entity& rEntity = getEntity();
     984             : 
     985             :     // set all necessary C-Callbacks
     986             :     static xmlSAXHandler callbacks;
     987       22211 :     callbacks.startElementNs = call_callbackStartElement;
     988       22211 :     callbacks.endElementNs = call_callbackEndElement;
     989       22211 :     callbacks.characters = call_callbackCharacters;
     990       22211 :     callbacks.initialized = XML_SAX2_MAGIC;
     991             : #if 0
     992             :     XML_SetEntityDeclHandler(entity.mpParser, call_callbackEntityDecl);
     993             :     XML_SetExternalEntityRefHandler( entity.mpParser, call_callbackExternalEntityRef );
     994             : #endif
     995       22211 :     int nRead = 0;
     996       25385 :     do
     997             :     {
     998       47596 :         nRead = rEntity.maConverter.readAndConvert( seqOut, BUFFER_SIZE );
     999       47596 :         if( nRead <= 0 )
    1000             :         {
    1001       22211 :             if( rEntity.mpParser != NULL )
    1002             :             {
    1003       22211 :                 if( xmlParseChunk( rEntity.mpParser, reinterpret_cast<const char*>(seqOut.getConstArray()), 0, 1 ) != XML_ERR_OK )
    1004           2 :                     rEntity.throwException( mxDocumentLocator, true );
    1005             :             }
    1006       22209 :             break;
    1007             :         }
    1008             : 
    1009       25385 :         bool bContinue = true;
    1010       25385 :         if( rEntity.mpParser == NULL )
    1011             :         {
    1012             :             // create parser with proper encoding (needs the first chunk of data)
    1013             :             rEntity.mpParser = xmlCreatePushParserCtxt( &callbacks, this,
    1014       22211 :                 reinterpret_cast<const char*>(seqOut.getConstArray()), nRead, NULL );
    1015       22211 :             if( !rEntity.mpParser )
    1016           0 :                 throw SAXException("Couldn't create parser", Reference< XInterface >(), Any() );
    1017             : 
    1018             :             // Tell libxml2 parser to decode entities in attribute values.
    1019       22211 :             xmlCtxtUseOptions(rEntity.mpParser, XML_PARSE_NOENT);
    1020             :         }
    1021             :         else
    1022             :         {
    1023        3174 :             bContinue = xmlParseChunk( rEntity.mpParser, reinterpret_cast<const char*>(seqOut.getConstArray()), nRead, 0 )
    1024        3174 :                             == XML_ERR_OK;
    1025             :         }
    1026             : 
    1027             :         // callbacks used inside XML_Parse may have caught an exception
    1028       25385 :         if( !bContinue || rEntity.maSavedException.hasValue() )
    1029           0 :             rEntity.throwException( mxDocumentLocator, true );
    1030             :     } while( nRead > 0 );
    1031       22209 :     rEntity.getEvent( DONE );
    1032       22209 :     if( rEntity.mbEnableThreads )
    1033        1570 :         produce( true );
    1034       22209 : }
    1035             : 
    1036             : // The C-Callbacks
    1037     2432018 : void FastSaxParserImpl::callbackStartElement(const xmlChar *localName , const xmlChar* prefix, const xmlChar* URI,
    1038             :     int numNamespaces, const xmlChar** namespaces, int numAttributes, int /*defaultedAttributes*/, const xmlChar **attributes)
    1039             : {
    1040     2432018 :     if( !pendingCharacters.isEmpty())
    1041       47245 :         sendPendingCharacters();
    1042     2432018 :     Entity& rEntity = getEntity();
    1043     2432018 :     if( rEntity.maNamespaceCount.empty() )
    1044             :     {
    1045       22211 :         rEntity.maNamespaceCount.push(0);
    1046       22211 :         DefineNamespace( OString("xml"), OUString( "http://www.w3.org/XML/1998/namespace" ));
    1047             :     }
    1048             :     else
    1049             :     {
    1050     2409807 :         rEntity.maNamespaceCount.push( rEntity.maNamespaceCount.top() );
    1051             :     }
    1052             : 
    1053             :     // create attribute map and process namespace instructions
    1054     2432018 :     Event& rEvent = getEntity().getEvent( START_ELEMENT );
    1055     2432018 :     if (rEvent.mxAttributes.is())
    1056     1872159 :         rEvent.mxAttributes->clear();
    1057             :     else
    1058             :         rEvent.mxAttributes.set(
    1059             :                 new FastAttributeList( rEntity.mxTokenHandler,
    1060      559859 :                                        rEntity.mpTokenHandler ) );
    1061             : 
    1062     2432018 :     sal_Int32 nNamespaceToken = FastToken::DONTKNOW;
    1063     2432018 :     if (!rEntity.maNamespaceStack.empty())
    1064             :     {
    1065     2409807 :         rEvent.msNamespace = rEntity.maNamespaceStack.top().msName;
    1066     2409807 :         nNamespaceToken = rEntity.maNamespaceStack.top().mnToken;
    1067             :     }
    1068             : 
    1069             :     try
    1070             :     {
    1071             :         /*  #158414# Each element may define new namespaces, also for attribues.
    1072             :             First, process all namespaces, second, process the attributes after namespaces
    1073             :             have been initialized. */
    1074             : 
    1075             :         // #158414# first: get namespaces
    1076     2525410 :         for (int i = 0; i < numNamespaces * 2; i += 2)
    1077             :         {
    1078             :             // namespaces[] is (prefix/URI)
    1079       93392 :             if( namespaces[ i ] != NULL )
    1080             :             {
    1081       84182 :                     DefineNamespace( OString( XML_CAST( namespaces[ i ] )),
    1082      168364 :                         OUString( XML_CAST( namespaces[ i + 1 ] ), strlen( XML_CAST( namespaces[ i + 1 ] )), RTL_TEXTENCODING_UTF8 ));
    1083             :             }
    1084             :             else
    1085             :             {
    1086             :                 // default namespace
    1087        9210 :                 rEvent.msNamespace = OUString( XML_CAST( namespaces[ i + 1 ] ), strlen( XML_CAST( namespaces[ i + 1 ] )), RTL_TEXTENCODING_UTF8 );
    1088        9210 :                 nNamespaceToken = GetNamespaceToken( rEvent.msNamespace );
    1089             :             }
    1090             :         }
    1091             : 
    1092             :         // #158414# second: fill attribute list with other attributes
    1093     5699732 :         for (int i = 0; i < numAttributes * 5; i += 5)
    1094             :         {
    1095     3267714 :             if( attributes[ i + 1 ] != NULL )
    1096             :             {
    1097     2464512 :                 sal_Int32 nAttributeToken = GetTokenWithPrefix( attributes[ i + 1 ], strlen( XML_CAST( attributes[ i + 1 ] )), attributes[ i ], strlen( XML_CAST( attributes[ i ] )));
    1098     2464512 :                 if( nAttributeToken != FastToken::DONTKNOW )
    1099     2445800 :                     rEvent.mxAttributes->add( nAttributeToken, XML_CAST( attributes[ i + 3 ] ), attributes[ i + 4 ] - attributes[ i + 3 ] );
    1100             :                 else
    1101       37424 :                     rEvent.mxAttributes->addUnknown( OUString( XML_CAST( attributes[ i + 2 ] ), strlen( XML_CAST( attributes[ i + 2 ] )), RTL_TEXTENCODING_UTF8 ),
    1102       56136 :                             OString( XML_CAST( attributes[ i ] )), OString( XML_CAST( attributes[ i + 3 ] ), attributes[ i + 4 ] - attributes[ i + 3 ] ));
    1103             :             }
    1104             :             else
    1105             :             {
    1106      803202 :                 sal_Int32 nAttributeToken = GetToken( attributes[ i ], strlen( XML_CAST( attributes[ i ] )));
    1107      803201 :                 if( nAttributeToken != FastToken::DONTKNOW )
    1108      801359 :                     rEvent.mxAttributes->add( nAttributeToken, XML_CAST( attributes[ i + 3 ] ), attributes[ i + 4 ] - attributes[ i + 3 ] );
    1109             :                 else
    1110        1842 :                     rEvent.mxAttributes->addUnknown( XML_CAST( attributes[ i ] ),
    1111        3684 :                         OString( XML_CAST( attributes[ i + 3 ] ), attributes[ i + 4 ] - attributes[ i + 3 ] ));
    1112             :             }
    1113             :         }
    1114             : 
    1115     2432018 :         if( prefix != NULL )
    1116     2322654 :             rEvent.mnElementToken = GetTokenWithPrefix( prefix, strlen( XML_CAST( prefix )), localName, strlen( XML_CAST( localName )));
    1117      109364 :         else if( !rEvent.msNamespace.isEmpty() )
    1118      109353 :             rEvent.mnElementToken = GetTokenWithContextNamespace( nNamespaceToken, localName, strlen( XML_CAST( localName )));
    1119             :         else
    1120          11 :             rEvent.mnElementToken = GetToken( localName, strlen( XML_CAST( localName )));
    1121             : 
    1122     2432017 :         if( rEvent.mnElementToken == FastToken::DONTKNOW )
    1123             :         {
    1124        7443 :             if( prefix != NULL )
    1125             :             {
    1126        5633 :                 rEvent.msNamespace = OUString( XML_CAST( URI ), strlen( XML_CAST( URI )), RTL_TEXTENCODING_UTF8 );
    1127        5633 :                 nNamespaceToken = GetNamespaceToken( rEvent.msNamespace );
    1128             :             }
    1129        7443 :             rEvent.msElementName = OUString( XML_CAST( localName ), strlen( XML_CAST( localName )), RTL_TEXTENCODING_UTF8 );
    1130             :         }
    1131             :         else // token is always preferred.
    1132     2424574 :             rEvent.msElementName.clear();
    1133             : 
    1134     2432017 :         rEntity.maNamespaceStack.push( NameWithToken(rEvent.msNamespace, nNamespaceToken) );
    1135     2432018 :         if (rEntity.mbEnableThreads)
    1136      555731 :             produce();
    1137             :         else
    1138     1876287 :             rEntity.startElement( &rEvent );
    1139             :     }
    1140           0 :     catch (const Exception&)
    1141             :     {
    1142           0 :         rEntity.saveException( ::cppu::getCaughtException() );
    1143             :     }
    1144     2432018 : }
    1145             : 
    1146     2432011 : void FastSaxParserImpl::callbackEndElement( const xmlChar*, const xmlChar*, const xmlChar* )
    1147             : {
    1148     2432011 :     if( !pendingCharacters.isEmpty())
    1149      126192 :         sendPendingCharacters();
    1150     2432011 :     Entity& rEntity = getEntity();
    1151             :     SAL_WARN_IF(rEntity.maNamespaceCount.empty(), "sax", "Empty NamespaceCount");
    1152     2432011 :     if( !rEntity.maNamespaceCount.empty() )
    1153     2432011 :         rEntity.maNamespaceCount.pop();
    1154             : 
    1155             :     SAL_WARN_IF(rEntity.maNamespaceStack.empty(), "sax", "Empty NamespaceStack");
    1156     2432011 :     if( !rEntity.maNamespaceStack.empty() )
    1157     2432011 :         rEntity.maNamespaceStack.pop();
    1158             : 
    1159     2432011 :     rEntity.getEvent( END_ELEMENT );
    1160     2432011 :     if (rEntity.mbEnableThreads)
    1161      555731 :         produce();
    1162             :     else
    1163     1876280 :         rEntity.endElement();
    1164     2432011 : }
    1165             : 
    1166      179028 : void FastSaxParserImpl::callbackCharacters( const xmlChar* s, int nLen )
    1167             : {
    1168             :     // SAX interface allows that the characters callback splits content of one XML node
    1169             :     // (e.g. because there's an entity that needs decoding), however for consumers it's
    1170             :     // simpler FastSaxParser's character callback provides the whole string at once,
    1171             :     // so merge data from possible multiple calls and send them at once (before the element
    1172             :     // ends or another one starts).
    1173      179028 :     pendingCharacters += OUString( XML_CAST( s ), nLen, RTL_TEXTENCODING_UTF8 );
    1174      179028 : }
    1175             : 
    1176      173437 : void FastSaxParserImpl::sendPendingCharacters()
    1177             : {
    1178      173437 :     Entity& rEntity = getEntity();
    1179      173437 :     Event& rEvent = rEntity.getEvent( CHARACTERS );
    1180      173437 :     rEvent.msChars = pendingCharacters;
    1181      173437 :     pendingCharacters.clear();
    1182      173437 :     if (rEntity.mbEnableThreads)
    1183       37166 :         produce();
    1184             :     else
    1185      136271 :         rEntity.characters( rEvent.msChars );
    1186      173437 : }
    1187             : 
    1188             : #if 0
    1189             : void FastSaxParserImpl::callbackEntityDecl(
    1190             :     SAL_UNUSED_PARAMETER const xmlChar * /*entityName*/,
    1191             :     SAL_UNUSED_PARAMETER int /*is_parameter_entity*/,
    1192             :     const xmlChar *value, SAL_UNUSED_PARAMETER int /*value_length*/,
    1193             :     SAL_UNUSED_PARAMETER const xmlChar * /*base*/,
    1194             :     SAL_UNUSED_PARAMETER const xmlChar * /*systemId*/,
    1195             :     SAL_UNUSED_PARAMETER const xmlChar * /*publicId*/,
    1196             :     SAL_UNUSED_PARAMETER const xmlChar * /*notationName*/)
    1197             : {
    1198             :     if (value) { // value != 0 means internal entity
    1199             :         SAL_INFO("sax", "FastSaxParser: internal entity declaration, stopping");
    1200             :         XML_StopParser(getEntity().mpParser, XML_FALSE);
    1201             :         getEntity().saveException( SAXParseException(
    1202             :             "FastSaxParser: internal entity declaration, stopping",
    1203             :             static_cast<OWeakObject*>(mpFront), Any(),
    1204             :             mxDocumentLocator->getPublicId(),
    1205             :             mxDocumentLocator->getSystemId(),
    1206             :             mxDocumentLocator->getLineNumber(),
    1207             :             mxDocumentLocator->getColumnNumber() ) );
    1208             :     } else {
    1209             :         SAL_INFO("sax", "FastSaxParser: ignoring external entity declaration");
    1210             :     }
    1211             : }
    1212             : 
    1213             : bool FastSaxParserImpl::callbackExternalEntityRef(
    1214             :     XML_Parser parser, const xmlChar *context,
    1215             :     SAL_UNUSED_PARAMETER const xmlChar * /*base*/, const xmlChar *systemId,
    1216             :     const xmlChar *publicId )
    1217             : {
    1218             :     bool bOK = true;
    1219             :     InputSource source;
    1220             : 
    1221             :     Entity& rCurrEntity = getEntity();
    1222             :     Entity aNewEntity( rCurrEntity );
    1223             : 
    1224             :     if( rCurrEntity.mxEntityResolver.is() ) try
    1225             :     {
    1226             :         aNewEntity.maStructSource = rCurrEntity.mxEntityResolver->resolveEntity(
    1227             :             OUString( publicId, strlen( publicId ), RTL_TEXTENCODING_UTF8 ) ,
    1228             :             OUString( systemId, strlen( systemId ), RTL_TEXTENCODING_UTF8 ) );
    1229             :     }
    1230             :     catch (const SAXParseException & e)
    1231             :     {
    1232             :         rCurrEntity.saveException( e );
    1233             :         bOK = false;
    1234             :     }
    1235             :     catch (const SAXException& e)
    1236             :     {
    1237             :         rCurrEntity.saveException( SAXParseException(
    1238             :             e.Message, e.Context, e.WrappedException,
    1239             :             mxDocumentLocator->getPublicId(),
    1240             :             mxDocumentLocator->getSystemId(),
    1241             :             mxDocumentLocator->getLineNumber(),
    1242             :             mxDocumentLocator->getColumnNumber() ) );
    1243             :         bOK = false;
    1244             :     }
    1245             : 
    1246             :     if( aNewEntity.maStructSource.aInputStream.is() )
    1247             :     {
    1248             :         aNewEntity.mpParser = XML_ExternalEntityParserCreate( parser, context, 0 );
    1249             :         if( !aNewEntity.mpParser )
    1250             :         {
    1251             :             return false;
    1252             :         }
    1253             : 
    1254             :         aNewEntity.maConverter.setInputStream( aNewEntity.maStructSource.aInputStream );
    1255             :         pushEntity( aNewEntity );
    1256             :         try
    1257             :         {
    1258             :             parse();
    1259             :         }
    1260             :         catch (const SAXParseException& e)
    1261             :         {
    1262             :             rCurrEntity.saveException( e );
    1263             :             bOK = false;
    1264             :         }
    1265             :         catch (const IOException& e)
    1266             :         {
    1267             :             SAXException aEx;
    1268             :             aEx.WrappedException <<= e;
    1269             :             rCurrEntity.saveException( aEx );
    1270             :             bOK = false;
    1271             :         }
    1272             :         catch (const RuntimeException& e)
    1273             :         {
    1274             :             SAXException aEx;
    1275             :             aEx.WrappedException <<= e;
    1276             :             rCurrEntity.saveException( aEx );
    1277             :             bOK = false;
    1278             :         }
    1279             : 
    1280             :         popEntity();
    1281             :         XML_ParserFree( aNewEntity.mpParser );
    1282             :     }
    1283             : 
    1284             :     return bOK;
    1285             : }
    1286             : #endif
    1287             : 
    1288       30005 : FastSaxParser::FastSaxParser() : mpImpl(new FastSaxParserImpl(this)) {}
    1289             : 
    1290       90014 : FastSaxParser::~FastSaxParser()
    1291             : {
    1292       30005 :     delete mpImpl;
    1293       60009 : }
    1294             : 
    1295       22427 : void FastSaxParser::parseStream( const xml::sax::InputSource& aInputSource )
    1296             :     throw (xml::sax::SAXException, io::IOException,
    1297             :            uno::RuntimeException, std::exception)
    1298             : {
    1299       22427 :     mpImpl->parseStream(aInputSource);
    1300       22209 : }
    1301             : 
    1302       28567 : void FastSaxParser::setFastDocumentHandler( const uno::Reference<xml::sax::XFastDocumentHandler>& Handler )
    1303             :     throw (uno::RuntimeException, std::exception)
    1304             : {
    1305       28567 :     mpImpl->setFastDocumentHandler(Handler);
    1306       28567 : }
    1307             : 
    1308       30003 : void FastSaxParser::setTokenHandler( const uno::Reference<xml::sax::XFastTokenHandler>& Handler )
    1309             :     throw (uno::RuntimeException, std::exception)
    1310             : {
    1311       30003 :     mpImpl->setTokenHandler(Handler);
    1312       30003 : }
    1313             : 
    1314     1368704 : void FastSaxParser::registerNamespace( const OUString& NamespaceURL, sal_Int32 NamespaceToken )
    1315             :     throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
    1316             : {
    1317     1368704 :     mpImpl->registerNamespace(NamespaceURL, NamespaceToken);
    1318     1368704 : }
    1319             : 
    1320           0 : OUString FastSaxParser::getNamespaceURL( const OUString& rPrefix )
    1321             :     throw(lang::IllegalArgumentException, uno::RuntimeException, std::exception)
    1322             : {
    1323           0 :     return mpImpl->getNamespaceURL(rPrefix);
    1324             : }
    1325             : 
    1326           0 : void FastSaxParser::setErrorHandler( const uno::Reference< xml::sax::XErrorHandler >& Handler )
    1327             :     throw (uno::RuntimeException, std::exception)
    1328             : {
    1329           0 :     mpImpl->setErrorHandler(Handler);
    1330           0 : }
    1331             : 
    1332           0 : void FastSaxParser::setEntityResolver( const uno::Reference< xml::sax::XEntityResolver >& Resolver )
    1333             :     throw (uno::RuntimeException, std::exception)
    1334             : {
    1335           0 :     mpImpl->setEntityResolver(Resolver);
    1336           0 : }
    1337             : 
    1338           0 : void FastSaxParser::setLocale( const lang::Locale& rLocale )
    1339             :     throw (uno::RuntimeException, std::exception)
    1340             : {
    1341           0 :     mpImpl->setLocale(rLocale);
    1342           0 : }
    1343             : 
    1344           1 : OUString FastSaxParser::getImplementationName()
    1345             :     throw (uno::RuntimeException, std::exception)
    1346             : {
    1347           1 :     return OUString("com.sun.star.comp.extensions.xml.sax.FastParser");
    1348             : }
    1349             : 
    1350           0 : sal_Bool FastSaxParser::supportsService( const OUString& ServiceName )
    1351             :     throw (uno::RuntimeException, std::exception)
    1352             : {
    1353           0 :     return cppu::supportsService(this, ServiceName);
    1354             : }
    1355             : 
    1356           1 : uno::Sequence<OUString> FastSaxParser::getSupportedServiceNames()
    1357             :     throw (uno::RuntimeException, std::exception)
    1358             : {
    1359           1 :     Sequence<OUString> seq(1);
    1360           1 :     seq[0] = "com.sun.star.xml.sax.FastParser";
    1361           1 :     return seq;
    1362             : }
    1363             : 
    1364         129 : bool FastSaxParser::hasNamespaceURL( const OUString& rPrefix ) const
    1365             : {
    1366         129 :     return mpImpl->hasNamespaceURL(rPrefix);
    1367             : }
    1368             : 
    1369             : } // namespace sax_fastparser
    1370             : 
    1371             : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
    1372       30004 : com_sun_star_comp_extensions_xml_sax_FastParser_get_implementation(
    1373             :     css::uno::XComponentContext *,
    1374             :     css::uno::Sequence<css::uno::Any> const &)
    1375             : {
    1376       30004 :     return cppu::acquire(new FastSaxParser);
    1377             : }
    1378             : 
    1379             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11