summaryrefslogtreecommitdiffstats
path: root/sax/source/expatwrap/sax_expat.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sax/source/expatwrap/sax_expat.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream/1%7.0.4.tar.xz
libreoffice-upstream/1%7.0.4.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sax/source/expatwrap/sax_expat.cxx')
-rw-r--r--sax/source/expatwrap/sax_expat.cxx959
1 files changed, 959 insertions, 0 deletions
diff --git a/sax/source/expatwrap/sax_expat.cxx b/sax/source/expatwrap/sax_expat.cxx
new file mode 100644
index 000000000..b80ebf033
--- /dev/null
+++ b/sax/source/expatwrap/sax_expat.cxx
@@ -0,0 +1,959 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+#include <cassert>
+#include <memory>
+#include <utility>
+#include <vector>
+
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
+#include <com/sun/star/xml/sax/XParser.hpp>
+#include <com/sun/star/xml/sax/SAXParseException.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+
+#include <comphelper/attributelist.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/ref.hxx>
+#include <sal/log.hxx>
+
+#include <expat.h>
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::xml::sax;
+using namespace ::com::sun::star::io;
+
+#include <xml2utf.hxx>
+
+namespace {
+
+#define XML_CHAR_TO_OUSTRING(x) OUString(x , strlen( x ), RTL_TEXTENCODING_UTF8)
+#define XML_CHAR_N_TO_USTRING(x,n) OUString(x,n, RTL_TEXTENCODING_UTF8 )
+
+
+/*
+* The following macro encapsulates any call to an event handler.
+* It ensures, that exceptions thrown by the event handler are
+* treated properly.
+*/
+#define CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(pThis,call) \
+ if( ! pThis->bExceptionWasThrown ) { \
+ try {\
+ pThis->call;\
+ }\
+ catch( const SAXParseException &e ) {\
+ callErrorHandler( pThis , e );\
+ }\
+ catch( const SAXException &e ) {\
+ callErrorHandler( pThis , SAXParseException(\
+ e.Message, \
+ e.Context, \
+ e.WrappedException,\
+ pThis->rDocumentLocator->getPublicId(),\
+ pThis->rDocumentLocator->getSystemId(),\
+ pThis->rDocumentLocator->getLineNumber(),\
+ pThis->rDocumentLocator->getColumnNumber()\
+ ) );\
+ }\
+ catch( const css::uno::RuntimeException &e ) {\
+ pThis->bExceptionWasThrown = true; \
+ pThis->bRTExceptionWasThrown = true; \
+ pImpl->rtexception = e; \
+ }\
+ catch( const css::uno::Exception &e ) {\
+ pThis->bExceptionWasThrown = true; \
+ pThis->bRTExceptionWasThrown = true; \
+ pImpl->rtexception = WrappedTargetRuntimeException("Non-runtime UNO exception caught during parse", e.Context, makeAny(e)); \
+ }\
+ }\
+ ((void)0)
+
+
+class SaxExpatParser_Impl;
+
+// This class implements the external Parser interface
+class SaxExpatParser
+ : public WeakImplHelper< XInitialization
+ , XServiceInfo
+ , XParser >
+{
+
+public:
+ SaxExpatParser();
+
+ // css::lang::XInitialization:
+ virtual void SAL_CALL initialize(css::uno::Sequence<css::uno::Any> const& rArguments) override;
+
+ // The SAX-Parser-Interface
+ virtual void SAL_CALL parseStream( const InputSource& structSource) override;
+ virtual void SAL_CALL setDocumentHandler(const css::uno::Reference< XDocumentHandler > & xHandler) override;
+
+ virtual void SAL_CALL setErrorHandler(const css::uno::Reference< XErrorHandler > & xHandler) override;
+ virtual void SAL_CALL setDTDHandler(const css::uno::Reference < XDTDHandler > & xHandler) override;
+ virtual void SAL_CALL setEntityResolver(const css::uno::Reference< XEntityResolver >& xResolver) override;
+
+ virtual void SAL_CALL setLocale( const Locale &locale ) override;
+
+public: // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+
+private:
+ std::unique_ptr<SaxExpatParser_Impl> m_pImpl;
+};
+
+
+// Entity binds all information needed for a single file
+struct Entity
+{
+ InputSource structSource;
+ XML_Parser pParser;
+ sax_expatwrap::XMLFile2UTFConverter converter;
+};
+
+
+static constexpr OUStringLiteral gsCDATA = "CDATA";
+
+class SaxExpatParser_Impl
+{
+public: // module scope
+ Mutex aMutex;
+ bool m_bEnableDoS; // fdo#60471 thank you Adobe Illustrator
+
+ css::uno::Reference< XDocumentHandler > rDocumentHandler;
+ css::uno::Reference< XExtendedDocumentHandler > rExtendedDocumentHandler;
+
+ css::uno::Reference< XErrorHandler > rErrorHandler;
+ css::uno::Reference< XDTDHandler > rDTDHandler;
+ css::uno::Reference< XEntityResolver > rEntityResolver;
+ css::uno::Reference < XLocator > rDocumentLocator;
+
+
+ rtl::Reference < comphelper::AttributeList > rAttrList;
+
+ // External entity stack
+ vector<struct Entity> vecEntity;
+ void pushEntity( Entity &&entity )
+ { vecEntity.push_back( std::move(entity) ); }
+ void popEntity()
+ { vecEntity.pop_back( ); }
+ struct Entity &getEntity()
+ { return vecEntity.back(); }
+
+
+ // Exception cannot be thrown through the C-XmlParser (possible resource leaks),
+ // therefore the exception must be saved somewhere.
+ SAXParseException exception;
+ css::uno::RuntimeException rtexception;
+ bool bExceptionWasThrown;
+ bool bRTExceptionWasThrown;
+
+public:
+ SaxExpatParser_Impl()
+ : m_bEnableDoS(false)
+ , bExceptionWasThrown(false)
+ , bRTExceptionWasThrown(false)
+ {
+ }
+
+ // the C-Callbacks for the expat parser
+ void static callbackStartElement(void *userData, const XML_Char *name , const XML_Char **atts);
+ void static callbackEndElement(void *userData, const XML_Char *name);
+ void static callbackCharacters( void *userData , const XML_Char *s , int nLen );
+ void static callbackProcessingInstruction( void *userData ,
+ const XML_Char *sTarget ,
+ const XML_Char *sData );
+
+ void static callbackEntityDecl( void *userData ,
+ const XML_Char *entityName,
+ int is_parameter_entity,
+ const XML_Char *value,
+ int value_length,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId,
+ const XML_Char *notationName);
+
+ void static callbackNotationDecl( void *userData,
+ const XML_Char *notationName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+ bool static callbackExternalEntityRef( XML_Parser parser,
+ const XML_Char *openEntityNames,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+ int static callbackUnknownEncoding(void *encodingHandlerData,
+ const XML_Char *name,
+ XML_Encoding *info);
+
+ void static callbackDefault( void *userData, const XML_Char *s, int len);
+
+ void static callbackStartCDATA( void *userData );
+ void static callbackEndCDATA( void *userData );
+ void static callbackComment( void *userData , const XML_Char *s );
+ void static callErrorHandler( SaxExpatParser_Impl *pImpl , const SAXParseException &e );
+
+public:
+ void parse();
+};
+
+extern "C"
+{
+ static void call_callbackStartElement(void *userData, const XML_Char *name , const XML_Char **atts)
+ {
+ SaxExpatParser_Impl::callbackStartElement(userData,name,atts);
+ }
+ static void call_callbackEndElement(void *userData, const XML_Char *name)
+ {
+ SaxExpatParser_Impl::callbackEndElement(userData,name);
+ }
+ static void call_callbackCharacters( void *userData , const XML_Char *s , int nLen )
+ {
+ SaxExpatParser_Impl::callbackCharacters(userData,s,nLen);
+ }
+ static void call_callbackProcessingInstruction(void *userData,const XML_Char *sTarget,const XML_Char *sData )
+ {
+ SaxExpatParser_Impl::callbackProcessingInstruction(userData,sTarget,sData );
+ }
+ static void call_callbackEntityDecl(void *userData ,
+ const XML_Char *entityName,
+ int is_parameter_entity,
+ const XML_Char *value,
+ int value_length,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId,
+ const XML_Char *notationName)
+ {
+ SaxExpatParser_Impl::callbackEntityDecl(userData, entityName,
+ is_parameter_entity, value, value_length,
+ base, systemId, publicId, notationName);
+ }
+ static void call_callbackNotationDecl(void *userData,
+ const XML_Char *notationName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId)
+ {
+ SaxExpatParser_Impl::callbackNotationDecl(userData,notationName,base,systemId,publicId);
+ }
+ static int call_callbackExternalEntityRef(XML_Parser parser,
+ const XML_Char *openEntityNames,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId)
+ {
+ return SaxExpatParser_Impl::callbackExternalEntityRef(parser,openEntityNames,base,systemId,publicId);
+ }
+ static int call_callbackUnknownEncoding(void *encodingHandlerData,
+ const XML_Char *name,
+ XML_Encoding *info)
+ {
+ return SaxExpatParser_Impl::callbackUnknownEncoding(encodingHandlerData,name,info);
+ }
+ static void call_callbackDefault( void *userData, const XML_Char *s, int len)
+ {
+ SaxExpatParser_Impl::callbackDefault(userData,s,len);
+ }
+ static void call_callbackStartCDATA( void *userData )
+ {
+ SaxExpatParser_Impl::callbackStartCDATA(userData);
+ }
+ static void call_callbackEndCDATA( void *userData )
+ {
+ SaxExpatParser_Impl::callbackEndCDATA(userData);
+ }
+ static void call_callbackComment( void *userData , const XML_Char *s )
+ {
+ SaxExpatParser_Impl::callbackComment(userData,s);
+ }
+}
+
+
+// LocatorImpl
+
+class LocatorImpl :
+ public WeakImplHelper< XLocator, css::io::XSeekable >
+ // should use a different interface for stream positions!
+{
+public:
+ explicit LocatorImpl(SaxExpatParser_Impl *p)
+ : m_pParser(p)
+ {
+ }
+
+public: //XLocator
+ virtual sal_Int32 SAL_CALL getColumnNumber() override
+ {
+ return XML_GetCurrentColumnNumber( m_pParser->getEntity().pParser );
+ }
+ virtual sal_Int32 SAL_CALL getLineNumber() override
+ {
+ return XML_GetCurrentLineNumber( m_pParser->getEntity().pParser );
+ }
+ virtual OUString SAL_CALL getPublicId() override
+ {
+ return m_pParser->getEntity().structSource.sPublicId;
+ }
+ virtual OUString SAL_CALL getSystemId() override
+ {
+ return m_pParser->getEntity().structSource.sSystemId;
+ }
+
+ // XSeekable (only for getPosition)
+
+ virtual void SAL_CALL seek( sal_Int64 ) override
+ {
+ }
+ virtual sal_Int64 SAL_CALL getPosition() override
+ {
+ return XML_GetCurrentByteIndex( m_pParser->getEntity().pParser );
+ }
+ virtual ::sal_Int64 SAL_CALL getLength() override
+ {
+ return 0;
+ }
+
+private:
+
+ SaxExpatParser_Impl *m_pParser;
+};
+
+
+SaxExpatParser::SaxExpatParser( )
+{
+ m_pImpl.reset( new SaxExpatParser_Impl );
+
+ LocatorImpl *pLoc = new LocatorImpl( m_pImpl.get() );
+ m_pImpl->rDocumentLocator.set( pLoc );
+
+ // Performance-improvement; handing out the same object with every call of
+ // the startElement callback is allowed (see sax-specification):
+ m_pImpl->rAttrList = new comphelper::AttributeList;
+
+ m_pImpl->bExceptionWasThrown = false;
+ m_pImpl->bRTExceptionWasThrown = false;
+}
+
+// css::lang::XInitialization:
+void SAL_CALL
+SaxExpatParser::initialize(css::uno::Sequence< css::uno::Any > const& rArguments)
+{
+ // possible arguments: a string "DoSmeplease"
+ if (rArguments.hasElements())
+ {
+ OUString str;
+ if ((rArguments[0] >>= str) && "DoSmeplease" == str)
+ {
+ MutexGuard guard( m_pImpl->aMutex );
+ m_pImpl->m_bEnableDoS = true;
+ }
+ }
+}
+
+class ParserCleanup
+{
+private:
+ SaxExpatParser_Impl& m_rParser;
+ XML_Parser m_xmlParser;
+public:
+ ParserCleanup(SaxExpatParser_Impl& rParser, XML_Parser xmlParser)
+ : m_rParser(rParser)
+ , m_xmlParser(xmlParser)
+ {
+ }
+ ~ParserCleanup()
+ {
+ m_rParser.popEntity();
+ //XML_ParserFree accepts a null arg
+ XML_ParserFree(m_xmlParser);
+ }
+};
+
+/***************
+*
+* parseStream does Parser-startup initializations. The SaxExpatParser_Impl::parse() method does
+* the file-specific initialization work. (During a parser run, external files may be opened)
+*
+****************/
+void SaxExpatParser::parseStream( const InputSource& structSource)
+{
+ // Only one text at one time
+ MutexGuard guard( m_pImpl->aMutex );
+
+
+ struct Entity entity;
+ entity.structSource = structSource;
+
+ if( ! entity.structSource.aInputStream.is() )
+ {
+ throw SAXException("No input source",
+ css::uno::Reference< css::uno::XInterface > () , css::uno::Any() );
+ }
+
+ entity.converter.setInputStream( entity.structSource.aInputStream );
+ if( !entity.structSource.sEncoding.isEmpty() )
+ {
+ entity.converter.setEncoding(
+ OUStringToOString( entity.structSource.sEncoding , RTL_TEXTENCODING_ASCII_US ) );
+ }
+
+ // create parser with proper encoding
+ entity.pParser = XML_ParserCreate( nullptr );
+ if( ! entity.pParser )
+ {
+ throw SAXException("Couldn't create parser",
+ css::uno::Reference< css::uno::XInterface > (), css::uno::Any() );
+ }
+
+ // set all necessary C-Callbacks
+ XML_SetUserData( entity.pParser, m_pImpl.get() );
+ XML_SetElementHandler( entity.pParser ,
+ call_callbackStartElement ,
+ call_callbackEndElement );
+ XML_SetCharacterDataHandler( entity.pParser , call_callbackCharacters );
+ XML_SetProcessingInstructionHandler(entity.pParser ,
+ call_callbackProcessingInstruction );
+ if (!m_pImpl->m_bEnableDoS)
+ {
+ XML_SetEntityDeclHandler(entity.pParser, call_callbackEntityDecl);
+ }
+ XML_SetNotationDeclHandler( entity.pParser, call_callbackNotationDecl );
+ XML_SetExternalEntityRefHandler( entity.pParser,
+ call_callbackExternalEntityRef);
+ XML_SetUnknownEncodingHandler( entity.pParser, call_callbackUnknownEncoding ,nullptr);
+
+ if( m_pImpl->rExtendedDocumentHandler.is() ) {
+
+ // These handlers just delegate calls to the ExtendedHandler. If no extended handler is
+ // given, these callbacks can be ignored
+ XML_SetDefaultHandlerExpand( entity.pParser, call_callbackDefault );
+ XML_SetCommentHandler( entity.pParser, call_callbackComment );
+ XML_SetCdataSectionHandler( entity.pParser ,
+ call_callbackStartCDATA ,
+ call_callbackEndCDATA );
+ }
+
+
+ m_pImpl->exception = SAXParseException();
+ auto const xmlParser = entity.pParser;
+ m_pImpl->pushEntity( std::move(entity) );
+
+ ParserCleanup aEnsureFree(*m_pImpl, xmlParser);
+
+ // start the document
+ if( m_pImpl->rDocumentHandler.is() ) {
+ m_pImpl->rDocumentHandler->setDocumentLocator( m_pImpl->rDocumentLocator );
+ m_pImpl->rDocumentHandler->startDocument();
+ }
+
+ m_pImpl->parse();
+
+ // finish document
+ if( m_pImpl->rDocumentHandler.is() ) {
+ m_pImpl->rDocumentHandler->endDocument();
+ }
+}
+
+void SaxExpatParser::setDocumentHandler(const css::uno::Reference< XDocumentHandler > & xHandler)
+{
+ m_pImpl->rDocumentHandler = xHandler;
+ m_pImpl->rExtendedDocumentHandler =
+ css::uno::Reference< XExtendedDocumentHandler >( xHandler , css::uno::UNO_QUERY );
+}
+
+void SaxExpatParser::setErrorHandler(const css::uno::Reference< XErrorHandler > & xHandler)
+{
+ m_pImpl->rErrorHandler = xHandler;
+}
+
+void SaxExpatParser::setDTDHandler(const css::uno::Reference< XDTDHandler > & xHandler)
+{
+ m_pImpl->rDTDHandler = xHandler;
+}
+
+void SaxExpatParser::setEntityResolver(const css::uno::Reference < XEntityResolver > & xResolver)
+{
+ m_pImpl->rEntityResolver = xResolver;
+}
+
+
+void SaxExpatParser::setLocale( const Locale & )
+{
+ // not implemented
+}
+
+// XServiceInfo
+OUString SaxExpatParser::getImplementationName()
+{
+ return "com.sun.star.comp.extensions.xml.sax.ParserExpat";
+}
+
+// XServiceInfo
+sal_Bool SaxExpatParser::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+css::uno::Sequence< OUString > SaxExpatParser::getSupportedServiceNames()
+{
+ return { "com.sun.star.xml.sax.Parser" };
+}
+
+
+/*---------------------------------------
+*
+* Helper functions and classes
+*
+*
+*-------------------------------------------*/
+OUString getErrorMessage( XML_Error xmlE, const OUString& sSystemId , sal_Int32 nLine )
+{
+ OUString Message;
+ if( XML_ERROR_NONE == xmlE ) {
+ Message = "No";
+ }
+ else if( XML_ERROR_NO_MEMORY == xmlE ) {
+ Message = "no memory";
+ }
+ else if( XML_ERROR_SYNTAX == xmlE ) {
+ Message = "syntax";
+ }
+ else if( XML_ERROR_NO_ELEMENTS == xmlE ) {
+ Message = "no elements";
+ }
+ else if( XML_ERROR_INVALID_TOKEN == xmlE ) {
+ Message = "invalid token";
+ }
+ else if( XML_ERROR_UNCLOSED_TOKEN == xmlE ) {
+ Message = "unclosed token";
+ }
+ else if( XML_ERROR_PARTIAL_CHAR == xmlE ) {
+ Message = "partial char";
+ }
+ else if( XML_ERROR_TAG_MISMATCH == xmlE ) {
+ Message = "tag mismatch";
+ }
+ else if( XML_ERROR_DUPLICATE_ATTRIBUTE == xmlE ) {
+ Message = "duplicate attribute";
+ }
+ else if( XML_ERROR_JUNK_AFTER_DOC_ELEMENT == xmlE ) {
+ Message = "junk after doc element";
+ }
+ else if( XML_ERROR_PARAM_ENTITY_REF == xmlE ) {
+ Message = "parameter entity reference";
+ }
+ else if( XML_ERROR_UNDEFINED_ENTITY == xmlE ) {
+ Message = "undefined entity";
+ }
+ else if( XML_ERROR_RECURSIVE_ENTITY_REF == xmlE ) {
+ Message = "recursive entity reference";
+ }
+ else if( XML_ERROR_ASYNC_ENTITY == xmlE ) {
+ Message = "async entity";
+ }
+ else if( XML_ERROR_BAD_CHAR_REF == xmlE ) {
+ Message = "bad char reference";
+ }
+ else if( XML_ERROR_BINARY_ENTITY_REF == xmlE ) {
+ Message = "binary entity reference";
+ }
+ else if( XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF == xmlE ) {
+ Message = "attribute external entity reference";
+ }
+ else if( XML_ERROR_MISPLACED_XML_PI == xmlE ) {
+ Message = "misplaced xml processing instruction";
+ }
+ else if( XML_ERROR_UNKNOWN_ENCODING == xmlE ) {
+ Message = "unknown encoding";
+ }
+ else if( XML_ERROR_INCORRECT_ENCODING == xmlE ) {
+ Message = "incorrect encoding";
+ }
+ else if( XML_ERROR_UNCLOSED_CDATA_SECTION == xmlE ) {
+ Message = "unclosed cdata section";
+ }
+ else if( XML_ERROR_EXTERNAL_ENTITY_HANDLING == xmlE ) {
+ Message = "external entity reference";
+ }
+ else if( XML_ERROR_NOT_STANDALONE == xmlE ) {
+ Message = "not standalone";
+ }
+
+ OUString str = "[" +
+ sSystemId +
+ " line " +
+ OUString::number( nLine ) +
+ "]: " +
+ Message +
+ "error";
+
+ return str;
+}
+
+
+// starts parsing with actual parser !
+void SaxExpatParser_Impl::parse( )
+{
+ const int nBufSize = 16*1024;
+
+ int nRead = nBufSize;
+ css::uno::Sequence< sal_Int8 > seqOut(nBufSize);
+
+ while( nRead ) {
+ nRead = getEntity().converter.readAndConvert( seqOut , nBufSize );
+
+ bool bContinue(false);
+
+ if( ! nRead ) {
+ // last call - must return OK
+ XML_Status const ret = XML_Parse( getEntity().pParser,
+ reinterpret_cast<const char *>(seqOut.getConstArray()),
+ 0 ,
+ 1 );
+ if (ret == XML_STATUS_OK) {
+ break;
+ }
+ } else {
+ bContinue = ( XML_Parse( getEntity().pParser,
+ reinterpret_cast<const char *>(seqOut.getConstArray()),
+ nRead,
+ 0 ) != XML_STATUS_ERROR );
+ }
+
+ if( ! bContinue || bExceptionWasThrown ) {
+
+ if ( bRTExceptionWasThrown )
+ throw rtexception;
+
+ // Error during parsing !
+ XML_Error xmlE = XML_GetErrorCode( getEntity().pParser );
+ OUString sSystemId = rDocumentLocator->getSystemId();
+ sal_Int32 nLine = rDocumentLocator->getLineNumber();
+
+ SAXParseException aExcept(
+ getErrorMessage(xmlE , sSystemId, nLine) ,
+ css::uno::Reference< css::uno::XInterface >(),
+ css::uno::Any( &exception , cppu::UnoType<decltype(exception)>::get() ),
+ rDocumentLocator->getPublicId(),
+ rDocumentLocator->getSystemId(),
+ rDocumentLocator->getLineNumber(),
+ rDocumentLocator->getColumnNumber()
+ );
+
+ if( rErrorHandler.is() ) {
+
+ // error handler is set, so the handler may throw the exception
+ css::uno::Any a;
+ a <<= aExcept;
+ rErrorHandler->fatalError( a );
+ }
+
+ // Error handler has not thrown an exception, but parsing cannot go on,
+ // so an exception MUST be thrown.
+ throw aExcept;
+ } // if( ! bContinue )
+ } // while
+}
+
+
+// The C-Callbacks
+
+
+void SaxExpatParser_Impl::callbackStartElement( void *pvThis ,
+ const XML_Char *pwName ,
+ const XML_Char **awAttributes )
+{
+ SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
+
+ if( !pImpl->rDocumentHandler.is() )
+ return;
+
+ int i = 0;
+ pImpl->rAttrList->Clear();
+
+ while( awAttributes[i] ) {
+ assert(awAttributes[i+1]);
+ pImpl->rAttrList->AddAttribute(
+ XML_CHAR_TO_OUSTRING( awAttributes[i] ) ,
+ gsCDATA, // expat doesn't know types
+ XML_CHAR_TO_OUSTRING( awAttributes[i+1] ) );
+ i +=2;
+ }
+
+ CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(
+ pImpl ,
+ rDocumentHandler->startElement( XML_CHAR_TO_OUSTRING( pwName ) ,
+ pImpl->rAttrList.get() ) );
+}
+
+void SaxExpatParser_Impl::callbackEndElement( void *pvThis , const XML_Char *pwName )
+{
+ SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
+
+ if( pImpl->rDocumentHandler.is() ) {
+ CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl,
+ rDocumentHandler->endElement( XML_CHAR_TO_OUSTRING( pwName ) ) );
+ }
+}
+
+
+void SaxExpatParser_Impl::callbackCharacters( void *pvThis , const XML_Char *s , int nLen )
+{
+ SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
+
+ if( pImpl->rDocumentHandler.is() ) {
+ CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl ,
+ rDocumentHandler->characters( XML_CHAR_N_TO_USTRING(s,nLen) ) );
+ }
+}
+
+void SaxExpatParser_Impl::callbackProcessingInstruction( void *pvThis,
+ const XML_Char *sTarget ,
+ const XML_Char *sData )
+{
+ SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
+ if( pImpl->rDocumentHandler.is() ) {
+ CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(
+ pImpl ,
+ rDocumentHandler->processingInstruction( XML_CHAR_TO_OUSTRING( sTarget ),
+ XML_CHAR_TO_OUSTRING( sData ) ) );
+ }
+}
+
+
+void SaxExpatParser_Impl::callbackEntityDecl(
+ void *pvThis, const XML_Char *entityName,
+ SAL_UNUSED_PARAMETER int /*is_parameter_entity*/,
+ const XML_Char *value, SAL_UNUSED_PARAMETER int /*value_length*/,
+ SAL_UNUSED_PARAMETER const XML_Char * /*base*/, const XML_Char *systemId,
+ const XML_Char *publicId, const XML_Char *notationName)
+{
+ SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
+ if (value) { // value != 0 means internal entity
+ SAL_INFO("sax","SaxExpatParser: internal entity declaration, stopping");
+ XML_StopParser(pImpl->getEntity().pParser, XML_FALSE);
+ pImpl->exception = SAXParseException(
+ "SaxExpatParser: internal entity declaration, stopping",
+ nullptr, css::uno::Any(),
+ pImpl->rDocumentLocator->getPublicId(),
+ pImpl->rDocumentLocator->getSystemId(),
+ pImpl->rDocumentLocator->getLineNumber(),
+ pImpl->rDocumentLocator->getColumnNumber() );
+ pImpl->bExceptionWasThrown = true;
+ } else {
+ if( pImpl->rDTDHandler.is() ) {
+ CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(
+ pImpl ,
+ rDTDHandler->unparsedEntityDecl(
+ XML_CHAR_TO_OUSTRING( entityName ),
+ XML_CHAR_TO_OUSTRING( publicId ) ,
+ XML_CHAR_TO_OUSTRING( systemId ) ,
+ XML_CHAR_TO_OUSTRING( notationName ) ) );
+ }
+ }
+}
+
+void SaxExpatParser_Impl::callbackNotationDecl(
+ void *pvThis, const XML_Char *notationName,
+ SAL_UNUSED_PARAMETER const XML_Char * /*base*/, const XML_Char *systemId,
+ const XML_Char *publicId)
+{
+ SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
+ if( pImpl->rDTDHandler.is() ) {
+ CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl,
+ rDTDHandler->notationDecl( XML_CHAR_TO_OUSTRING( notationName ) ,
+ XML_CHAR_TO_OUSTRING( publicId ) ,
+ XML_CHAR_TO_OUSTRING( systemId ) ) );
+ }
+
+}
+
+
+bool SaxExpatParser_Impl::callbackExternalEntityRef(
+ XML_Parser parser, const XML_Char *context,
+ SAL_UNUSED_PARAMETER const XML_Char * /*base*/, const XML_Char *systemId,
+ const XML_Char *publicId)
+{
+ bool bOK = true;
+ SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(XML_GetUserData( parser ));
+
+ struct Entity entity;
+
+ if( pImpl->rEntityResolver.is() ) {
+ try
+ {
+ entity.structSource = pImpl->rEntityResolver->resolveEntity(
+ XML_CHAR_TO_OUSTRING( publicId ) ,
+ XML_CHAR_TO_OUSTRING( systemId ) );
+ }
+ catch( const SAXParseException & e )
+ {
+ pImpl->exception = e;
+ bOK = false;
+ }
+ catch( const SAXException & e )
+ {
+ pImpl->exception = SAXParseException(
+ e.Message , e.Context , e.WrappedException ,
+ pImpl->rDocumentLocator->getPublicId(),
+ pImpl->rDocumentLocator->getSystemId(),
+ pImpl->rDocumentLocator->getLineNumber(),
+ pImpl->rDocumentLocator->getColumnNumber() );
+ bOK = false;
+ }
+ }
+
+ if( entity.structSource.aInputStream.is() ) {
+ entity.pParser = XML_ExternalEntityParserCreate( parser , context, nullptr );
+ if( ! entity.pParser )
+ {
+ return false;
+ }
+
+ entity.converter.setInputStream( entity.structSource.aInputStream );
+ auto const xmlParser = entity.pParser;
+ pImpl->pushEntity( std::move(entity) );
+ try
+ {
+ pImpl->parse();
+ }
+ catch( const SAXParseException & e )
+ {
+ pImpl->exception = e;
+ bOK = false;
+ }
+ catch( const IOException &e )
+ {
+ pImpl->exception.WrappedException <<= e;
+ bOK = false;
+ }
+ catch( const css::uno::RuntimeException &e )
+ {
+ pImpl->exception.WrappedException <<=e;
+ bOK = false;
+ }
+
+ pImpl->popEntity();
+
+ XML_ParserFree( xmlParser );
+ }
+
+ return bOK;
+}
+
+int SaxExpatParser_Impl::callbackUnknownEncoding(
+ SAL_UNUSED_PARAMETER void * /*encodingHandlerData*/,
+ SAL_UNUSED_PARAMETER const XML_Char * /*name*/,
+ SAL_UNUSED_PARAMETER XML_Encoding * /*info*/)
+{
+ return 0;
+}
+
+void SaxExpatParser_Impl::callbackDefault( void *pvThis, const XML_Char *s, int len)
+{
+ SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
+
+ CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl,
+ rExtendedDocumentHandler->unknown( XML_CHAR_N_TO_USTRING( s ,len) ) );
+}
+
+void SaxExpatParser_Impl::callbackComment( void *pvThis , const XML_Char *s )
+{
+ SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
+ CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl,
+ rExtendedDocumentHandler->comment( XML_CHAR_TO_OUSTRING( s ) ) );
+}
+
+void SaxExpatParser_Impl::callbackStartCDATA( void *pvThis )
+{
+ SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
+
+ CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl, rExtendedDocumentHandler->startCDATA() );
+}
+
+
+void SaxExpatParser_Impl::callErrorHandler( SaxExpatParser_Impl *pImpl ,
+ const SAXParseException & e )
+{
+ try
+ {
+ if( pImpl->rErrorHandler.is() ) {
+ css::uno::Any a;
+ a <<= e;
+ pImpl->rErrorHandler->error( a );
+ }
+ else {
+ pImpl->exception = e;
+ pImpl->bExceptionWasThrown = true;
+ }
+ }
+ catch( const SAXParseException & ex ) {
+ pImpl->exception = ex;
+ pImpl->bExceptionWasThrown = true;
+ }
+ catch( const SAXException & ex ) {
+ pImpl->exception = SAXParseException(
+ ex.Message,
+ ex.Context,
+ ex.WrappedException,
+ pImpl->rDocumentLocator->getPublicId(),
+ pImpl->rDocumentLocator->getSystemId(),
+ pImpl->rDocumentLocator->getLineNumber(),
+ pImpl->rDocumentLocator->getColumnNumber()
+ );
+ pImpl->bExceptionWasThrown = true;
+ }
+}
+
+void SaxExpatParser_Impl::callbackEndCDATA( void *pvThis )
+{
+ SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis);
+
+ CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(pImpl,rExtendedDocumentHandler->endCDATA() );
+}
+
+} // namespace
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_extensions_xml_sax_ParserExpat_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SaxExpatParser);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */