| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| //#include <stdlib.h> |
| //#include <sal/alloca.h> |
| |
| #include <boost/scoped_ptr.hpp> |
| |
| #include <osl/diagnose.h> |
| #include <rtl/ustrbuf.hxx> |
| |
| #include <com/sun/star/lang/DisposedException.hpp> |
| #include <com/sun/star/xml/sax/XFastContextHandler.hpp> |
| #include <com/sun/star/xml/sax/SAXParseException.hpp> |
| #include <com/sun/star/xml/sax/FastToken.hpp> |
| |
| #include "fastparser.hxx" |
| |
| #include <string.h> |
| |
| using ::rtl::OString; |
| using ::rtl::OUString; |
| using ::rtl::OUStringBuffer; |
| using namespace ::std; |
| using namespace ::osl; |
| using namespace ::cppu; |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star::lang; |
| using namespace ::com::sun::star::xml::sax; |
| //using namespace ::com::sun::star::util; |
| using namespace ::com::sun::star::io; |
| |
| namespace sax_fastparser { |
| |
| // -------------------------------------------------------------------- |
| |
| struct SaxContextImpl |
| { |
| Reference< XFastContextHandler > mxContext; |
| sal_uInt32 mnNamespaceCount; |
| sal_Int32 mnElementToken; |
| OUString maNamespace; |
| OUString maElementName; |
| |
| SaxContextImpl() { mnNamespaceCount = 0; mnElementToken = 0; } |
| SaxContextImpl( const SaxContextImplPtr& p ) { mnNamespaceCount = p->mnNamespaceCount; mnElementToken = p->mnElementToken; maNamespace = p->maNamespace; } |
| }; |
| |
| // -------------------------------------------------------------------- |
| |
| struct NamespaceDefine |
| { |
| OString maPrefix; |
| sal_Int32 mnToken; |
| OUString maNamespaceURL; |
| |
| NamespaceDefine( const OString& rPrefix, sal_Int32 nToken, const OUString& rNamespaceURL ) : maPrefix( rPrefix ), mnToken( nToken ), maNamespaceURL( rNamespaceURL ) {} |
| }; |
| |
| // -------------------------------------------------------------------- |
| // FastLocatorImpl |
| // -------------------------------------------------------------------- |
| |
| class FastSaxParser; |
| |
| class FastLocatorImpl : public WeakImplHelper1< XLocator > |
| { |
| public: |
| FastLocatorImpl( FastSaxParser *p ) : mpParser(p) {} |
| |
| void dispose() { mpParser = 0; } |
| void checkDispose() throw (RuntimeException) { if( !mpParser ) throw DisposedException(); } |
| |
| //XLocator |
| virtual sal_Int32 SAL_CALL getColumnNumber(void) throw (RuntimeException); |
| virtual sal_Int32 SAL_CALL getLineNumber(void) throw (RuntimeException); |
| virtual OUString SAL_CALL getPublicId(void) throw (RuntimeException); |
| virtual OUString SAL_CALL getSystemId(void) throw (RuntimeException); |
| |
| private: |
| FastSaxParser *mpParser; |
| }; |
| |
| // -------------------------------------------------------------------- |
| // FastSaxParser |
| // -------------------------------------------------------------------- |
| |
| //--------------------------------------------- |
| // the implementation part |
| //--------------------------------------------- |
| |
| extern "C" { |
| |
| static void call_callbackStartElement(void *userData, const XML_Char *name , const XML_Char **atts) |
| { |
| FastSaxParser* pFastParser = reinterpret_cast< FastSaxParser* >( userData ); |
| pFastParser->callbackStartElement( name, atts ); |
| } |
| |
| static void call_callbackEndElement(void *userData, const XML_Char *name) |
| { |
| FastSaxParser* pFastParser = reinterpret_cast< FastSaxParser* >( userData ); |
| pFastParser->callbackEndElement( name ); |
| } |
| |
| static void call_callbackCharacters( void *userData , const XML_Char *s , int nLen ) |
| { |
| FastSaxParser* pFastParser = reinterpret_cast< FastSaxParser* >( userData ); |
| pFastParser->callbackCharacters( s, nLen ); |
| } |
| |
| static int call_callbackExternalEntityRef( XML_Parser parser, |
| const XML_Char *openEntityNames, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId ) |
| { |
| FastSaxParser* pFastParser = reinterpret_cast< FastSaxParser* >( XML_GetUserData( parser ) ); |
| return pFastParser->callbackExternalEntityRef( parser, openEntityNames, base, systemId, publicId ); |
| } |
| |
| } // extern "C" |
| |
| // -------------------------------------------------------------------- |
| // FastLocatorImpl implementation |
| // -------------------------------------------------------------------- |
| |
| sal_Int32 SAL_CALL FastLocatorImpl::getColumnNumber(void) throw (RuntimeException) |
| { |
| checkDispose(); |
| return XML_GetCurrentColumnNumber( mpParser->getEntity().mpParser ); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| sal_Int32 SAL_CALL FastLocatorImpl::getLineNumber(void) throw (RuntimeException) |
| { |
| checkDispose(); |
| return XML_GetCurrentLineNumber( mpParser->getEntity().mpParser ); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| OUString SAL_CALL FastLocatorImpl::getPublicId(void) throw (RuntimeException) |
| { |
| checkDispose(); |
| return mpParser->getEntity().maStructSource.sPublicId; |
| } |
| // -------------------------------------------------------------------- |
| |
| OUString SAL_CALL FastLocatorImpl::getSystemId(void) throw (RuntimeException) |
| { |
| checkDispose(); |
| return mpParser->getEntity().maStructSource.sSystemId; |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| ParserData::ParserData() |
| { |
| } |
| |
| ParserData::~ParserData() |
| { |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| Entity::Entity( const ParserData& rData ) : |
| ParserData( rData ) |
| { |
| // performance-Improvment. Reference is needed when calling the startTag callback. |
| // Handing out the same object with every call is allowed (see sax-specification) |
| mxAttributes.set( new FastAttributeList( mxTokenHandler ) ); |
| } |
| |
| Entity::~Entity() |
| { |
| } |
| |
| // -------------------------------------------------------------------- |
| // FastSaxParser implementation |
| // -------------------------------------------------------------------- |
| |
| FastSaxParser::FastSaxParser() |
| { |
| mxDocumentLocator.set( new FastLocatorImpl( this ) ); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| FastSaxParser::~FastSaxParser() |
| { |
| if( mxDocumentLocator.is() ) |
| mxDocumentLocator->dispose(); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| void FastSaxParser::pushContext() |
| { |
| Entity& rEntity = getEntity(); |
| if( rEntity.maContextStack.empty() ) |
| { |
| rEntity.maContextStack.push( SaxContextImplPtr( new SaxContextImpl ) ); |
| DefineNamespace( OString("xml"), "http://www.w3.org/XML/1998/namespace"); |
| } |
| else |
| { |
| rEntity.maContextStack.push( SaxContextImplPtr( new SaxContextImpl( rEntity.maContextStack.top() ) ) ); |
| } |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| void FastSaxParser::popContext() |
| { |
| Entity& rEntity = getEntity(); |
| OSL_ENSURE( !rEntity.maContextStack.empty(), "sax::FastSaxParser::popContext(), pop without push?" ); |
| if( !rEntity.maContextStack.empty() ) |
| rEntity.maContextStack.pop(); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| void FastSaxParser::DefineNamespace( const OString& rPrefix, const sal_Char* pNamespaceURL ) |
| { |
| Entity& rEntity = getEntity(); |
| OSL_ENSURE( !rEntity.maContextStack.empty(), "sax::FastSaxParser::DefineNamespace(), I need a context!" ); |
| if( !rEntity.maContextStack.empty() ) |
| { |
| sal_uInt32 nOffset = rEntity.maContextStack.top()->mnNamespaceCount++; |
| |
| if( rEntity.maNamespaceDefines.size() <= nOffset ) |
| rEntity.maNamespaceDefines.resize( rEntity.maNamespaceDefines.size() + 64 ); |
| |
| const OUString aNamespaceURL( pNamespaceURL, strlen( pNamespaceURL ), RTL_TEXTENCODING_UTF8 ); |
| rEntity.maNamespaceDefines[nOffset].reset( new NamespaceDefine( rPrefix, GetNamespaceToken( aNamespaceURL ), aNamespaceURL ) ); |
| } |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| sal_Int32 FastSaxParser::GetToken( const OString& rToken ) |
| { |
| Sequence< sal_Int8 > aSeq( (sal_Int8*)rToken.getStr(), rToken.getLength() ); |
| |
| return getEntity().mxTokenHandler->getTokenFromUTF8( aSeq ); |
| } |
| |
| sal_Int32 FastSaxParser::GetToken( const sal_Char* pToken, sal_Int32 nLen /* = 0 */ ) |
| { |
| if( !nLen ) |
| nLen = strlen( pToken ); |
| |
| Sequence< sal_Int8 > aSeq( (sal_Int8*)pToken, nLen ); |
| |
| return getEntity().mxTokenHandler->getTokenFromUTF8( aSeq ); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| sal_Int32 FastSaxParser::GetTokenWithPrefix( const OString& rPrefix, const OString& rName ) throw (SAXException) |
| { |
| sal_Int32 nNamespaceToken = FastToken::DONTKNOW; |
| |
| Entity& rEntity = getEntity(); |
| sal_uInt32 nNamespace = rEntity.maContextStack.top()->mnNamespaceCount; |
| while( nNamespace-- ) |
| { |
| if( rEntity.maNamespaceDefines[nNamespace]->maPrefix == rPrefix ) |
| { |
| nNamespaceToken = rEntity.maNamespaceDefines[nNamespace]->mnToken; |
| break; |
| } |
| |
| if( !nNamespace ) |
| throw SAXException(); // prefix that has no defined namespace url |
| } |
| |
| if( nNamespaceToken != FastToken::DONTKNOW ) |
| { |
| sal_Int32 nNameToken = GetToken( rName.getStr(), rName.getLength() ); |
| if( nNameToken != FastToken::DONTKNOW ) |
| return nNamespaceToken | nNameToken; |
| } |
| |
| return FastToken::DONTKNOW; |
| } |
| |
| sal_Int32 FastSaxParser::GetTokenWithPrefix( const sal_Char*pPrefix, int nPrefixLen, const sal_Char* pName, int nNameLen ) throw (SAXException) |
| { |
| sal_Int32 nNamespaceToken = FastToken::DONTKNOW; |
| |
| Entity& rEntity = getEntity(); |
| sal_uInt32 nNamespace = rEntity.maContextStack.top()->mnNamespaceCount; |
| while( nNamespace-- ) |
| { |
| const OString& rPrefix( rEntity.maNamespaceDefines[nNamespace]->maPrefix ); |
| if( (rPrefix.getLength() == nPrefixLen) && |
| (strncmp( rPrefix.getStr(), pPrefix, nPrefixLen ) == 0 ) ) |
| { |
| nNamespaceToken = rEntity.maNamespaceDefines[nNamespace]->mnToken; |
| break; |
| } |
| |
| if( !nNamespace ) |
| throw SAXException(); // prefix that has no defined namespace url |
| } |
| |
| if( nNamespaceToken != FastToken::DONTKNOW ) |
| { |
| sal_Int32 nNameToken = GetToken( pName, nNameLen ); |
| if( nNameToken != FastToken::DONTKNOW ) |
| return nNamespaceToken | nNameToken; |
| } |
| |
| return FastToken::DONTKNOW; |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| sal_Int32 FastSaxParser::GetNamespaceToken( const OUString& rNamespaceURL ) |
| { |
| NamespaceMap::iterator aIter( maNamespaceMap.find( rNamespaceURL ) ); |
| if( aIter != maNamespaceMap.end() ) |
| return (*aIter).second; |
| else |
| return FastToken::DONTKNOW; |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| OUString FastSaxParser::GetNamespaceURL( const OString& rPrefix ) throw (SAXException) |
| { |
| Entity& rEntity = getEntity(); |
| if( !rEntity.maContextStack.empty() ) |
| { |
| sal_uInt32 nNamespace = rEntity.maContextStack.top()->mnNamespaceCount; |
| while( nNamespace-- ) |
| if( rEntity.maNamespaceDefines[nNamespace]->maPrefix == rPrefix ) |
| return rEntity.maNamespaceDefines[nNamespace]->maNamespaceURL; |
| } |
| |
| throw SAXException(); // prefix that has no defined namespace url |
| } |
| |
| OUString FastSaxParser::GetNamespaceURL( const sal_Char*pPrefix, int nPrefixLen ) throw(SAXException) |
| { |
| Entity& rEntity = getEntity(); |
| if( pPrefix && !rEntity.maContextStack.empty() ) |
| { |
| sal_uInt32 nNamespace = rEntity.maContextStack.top()->mnNamespaceCount; |
| while( nNamespace-- ) |
| { |
| const OString& rPrefix( rEntity.maNamespaceDefines[nNamespace]->maPrefix ); |
| if( (rPrefix.getLength() == nPrefixLen) && |
| (strncmp( rPrefix.getStr(), pPrefix, nPrefixLen ) == 0 ) ) |
| { |
| return rEntity.maNamespaceDefines[nNamespace]->maNamespaceURL; |
| } |
| } |
| } |
| |
| throw SAXException(); // prefix that has no defined namespace url |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| sal_Int32 FastSaxParser::GetTokenWithNamespaceURL( const OUString& rNamespaceURL, const sal_Char* pName, int nNameLen ) |
| { |
| sal_Int32 nNamespaceToken = GetNamespaceToken( rNamespaceURL ); |
| |
| if( nNamespaceToken != FastToken::DONTKNOW ) |
| { |
| sal_Int32 nNameToken = GetToken( pName, nNameLen ); |
| if( nNameToken != FastToken::DONTKNOW ) |
| return nNamespaceToken | nNameToken; |
| } |
| |
| return FastToken::DONTKNOW; |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| void FastSaxParser::splitName( const XML_Char *pwName, const XML_Char *&rpPrefix, sal_Int32 &rPrefixLen, const XML_Char *&rpName, sal_Int32 &rNameLen ) |
| { |
| XML_Char *p; |
| for( p = const_cast< XML_Char* >( pwName ), rNameLen = 0, rPrefixLen = 0; *p; p++ ) |
| { |
| if( *p == ':' ) |
| { |
| rPrefixLen = p - pwName; |
| rNameLen = 0; |
| } |
| else |
| { |
| rNameLen++; |
| } |
| } |
| if( rPrefixLen ) |
| { |
| rpPrefix = pwName; |
| rpName = &pwName[ rPrefixLen + 1 ]; |
| } |
| else |
| { |
| rpPrefix = 0; |
| rpName = pwName; |
| } |
| } |
| |
| /*************** |
| * |
| * parseStream does Parser-startup initializations. The FastSaxParser::parse() method does |
| * the file-specific initialization work. (During a parser run, external files may be opened) |
| * |
| ****************/ |
| void FastSaxParser::parseStream( const InputSource& maStructSource) throw (SAXException, IOException, RuntimeException) |
| { |
| // Only one text at one time |
| MutexGuard guard( maMutex ); |
| |
| Entity entity( maData ); |
| entity.maStructSource = maStructSource; |
| |
| if( !entity.maStructSource.aInputStream.is() ) |
| throw SAXException( OUString( RTL_CONSTASCII_USTRINGPARAM( "No input source" ) ), Reference< XInterface >(), Any() ); |
| |
| entity.maConverter.setInputStream( entity.maStructSource.aInputStream ); |
| if( entity.maStructSource.sEncoding.getLength() ) |
| entity.maConverter.setEncoding( OUStringToOString( entity.maStructSource.sEncoding, RTL_TEXTENCODING_ASCII_US ) ); |
| |
| // create parser with proper encoding |
| entity.mpParser = XML_ParserCreate( 0 ); |
| if( !entity.mpParser ) |
| throw SAXException( OUString( RTL_CONSTASCII_USTRINGPARAM( "Couldn't create parser" ) ), Reference< XInterface >(), Any() ); |
| |
| // set all necessary C-Callbacks |
| XML_SetUserData( entity.mpParser, this ); |
| XML_SetElementHandler( entity.mpParser, call_callbackStartElement, call_callbackEndElement ); |
| XML_SetCharacterDataHandler( entity.mpParser, call_callbackCharacters ); |
| XML_SetExternalEntityRefHandler( entity.mpParser, call_callbackExternalEntityRef ); |
| |
| pushEntity( entity ); |
| try |
| { |
| // start the document |
| if( entity.mxDocumentHandler.is() ) |
| { |
| Reference< XLocator > xLoc( mxDocumentLocator.get() ); |
| entity.mxDocumentHandler->setDocumentLocator( xLoc ); |
| entity.mxDocumentHandler->startDocument(); |
| } |
| |
| parse(); |
| |
| // finish document |
| if( entity.mxDocumentHandler.is() ) |
| { |
| entity.mxDocumentHandler->endDocument(); |
| } |
| } |
| catch( SAXException & ) |
| { |
| popEntity(); |
| XML_ParserFree( entity.mpParser ); |
| throw; |
| } |
| catch( IOException & ) |
| { |
| popEntity(); |
| XML_ParserFree( entity.mpParser ); |
| throw; |
| } |
| catch( RuntimeException & ) |
| { |
| popEntity(); |
| XML_ParserFree( entity.mpParser ); |
| throw; |
| } |
| |
| popEntity(); |
| XML_ParserFree( entity.mpParser ); |
| } |
| |
| void FastSaxParser::setFastDocumentHandler( const Reference< XFastDocumentHandler >& Handler ) throw (RuntimeException) |
| { |
| maData.mxDocumentHandler = Handler; |
| } |
| |
| void SAL_CALL FastSaxParser::setTokenHandler( const Reference< XFastTokenHandler >& Handler ) throw (RuntimeException) |
| { |
| maData.mxTokenHandler = Handler; |
| } |
| |
| void SAL_CALL FastSaxParser::registerNamespace( const OUString& NamespaceURL, sal_Int32 NamespaceToken ) throw (IllegalArgumentException, RuntimeException) |
| { |
| if( NamespaceToken >= FastToken::NAMESPACE ) |
| { |
| if( GetNamespaceToken( NamespaceURL ) == FastToken::DONTKNOW ) |
| { |
| maNamespaceMap[ NamespaceURL ] = NamespaceToken; |
| return; |
| } |
| } |
| throw IllegalArgumentException(); |
| } |
| |
| void FastSaxParser::setErrorHandler(const Reference< XErrorHandler > & Handler) throw (RuntimeException) |
| { |
| maData.mxErrorHandler = Handler; |
| } |
| |
| void FastSaxParser::setEntityResolver(const Reference < XEntityResolver > & Resolver) throw (RuntimeException) |
| { |
| maData.mxEntityResolver = Resolver; |
| } |
| |
| void FastSaxParser::setLocale( const Locale & Locale ) throw (RuntimeException) |
| { |
| maData.maLocale = Locale; |
| } |
| |
| Sequence< OUString > FastSaxParser::getSupportedServiceNames_Static(void) |
| { |
| Sequence<OUString> aRet(1); |
| aRet.getArray()[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(PARSER_SERVICE_NAME) ); |
| return aRet; |
| } |
| |
| // XServiceInfo |
| OUString FastSaxParser::getImplementationName() throw (RuntimeException) |
| { |
| return OUString::createFromAscii( PARSER_IMPLEMENTATION_NAME ); |
| } |
| |
| // XServiceInfo |
| sal_Bool FastSaxParser::supportsService(const OUString& ServiceName) throw (RuntimeException) |
| { |
| Sequence< OUString > aSNL = getSupportedServiceNames(); |
| const OUString * pArray = aSNL.getConstArray(); |
| |
| for( sal_Int32 i = 0; i < aSNL.getLength(); i++ ) |
| if( pArray[i] == ServiceName ) |
| return sal_True; |
| |
| return sal_False; |
| } |
| |
| // XServiceInfo |
| Sequence< OUString > FastSaxParser::getSupportedServiceNames(void) throw (RuntimeException) |
| { |
| |
| Sequence<OUString> seq(1); |
| seq.getArray()[0] = OUString::createFromAscii( PARSER_SERVICE_NAME ); |
| return seq; |
| } |
| |
| |
| /*--------------------------------------- |
| * |
| * Helper functions and classes |
| * |
| *-------------------------------------------*/ |
| |
| namespace { |
| |
| OUString lclGetErrorMessage( XML_Error xmlE, const OUString& sSystemId, sal_Int32 nLine ) |
| { |
| const sal_Char* pMessage = ""; |
| switch( xmlE ) |
| { |
| case XML_ERROR_NONE: pMessage = "No"; break; |
| case XML_ERROR_NO_MEMORY: pMessage = "no memory"; break; |
| case XML_ERROR_SYNTAX: pMessage = "syntax"; break; |
| case XML_ERROR_NO_ELEMENTS: pMessage = "no elements"; break; |
| case XML_ERROR_INVALID_TOKEN: pMessage = "invalid token"; break; |
| case XML_ERROR_UNCLOSED_TOKEN: pMessage = "unclosed token"; break; |
| case XML_ERROR_PARTIAL_CHAR: pMessage = "partial char"; break; |
| case XML_ERROR_TAG_MISMATCH: pMessage = "tag mismatch"; break; |
| case XML_ERROR_DUPLICATE_ATTRIBUTE: pMessage = "duplicate attribute"; break; |
| case XML_ERROR_JUNK_AFTER_DOC_ELEMENT: pMessage = "junk after doc element"; break; |
| case XML_ERROR_PARAM_ENTITY_REF: pMessage = "parameter entity reference"; break; |
| case XML_ERROR_UNDEFINED_ENTITY: pMessage = "undefined entity"; break; |
| case XML_ERROR_RECURSIVE_ENTITY_REF: pMessage = "recursive entity reference"; break; |
| case XML_ERROR_ASYNC_ENTITY: pMessage = "async entity"; break; |
| case XML_ERROR_BAD_CHAR_REF: pMessage = "bad char reference"; break; |
| case XML_ERROR_BINARY_ENTITY_REF: pMessage = "binary entity reference"; break; |
| case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF: pMessage = "attribute external entity reference"; break; |
| case XML_ERROR_MISPLACED_XML_PI: pMessage = "misplaced xml processing instruction"; break; |
| case XML_ERROR_UNKNOWN_ENCODING: pMessage = "unknown encoding"; break; |
| case XML_ERROR_INCORRECT_ENCODING: pMessage = "incorrect encoding"; break; |
| case XML_ERROR_UNCLOSED_CDATA_SECTION: pMessage = "unclosed cdata section"; break; |
| case XML_ERROR_EXTERNAL_ENTITY_HANDLING: pMessage = "external entity reference"; break; |
| case XML_ERROR_NOT_STANDALONE: pMessage = "not standalone"; break; |
| default:; |
| } |
| |
| OUStringBuffer aBuffer( sal_Unicode( '[' ) ); |
| aBuffer.append( sSystemId ); |
| aBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM( " line " ) ); |
| aBuffer.append( nLine ); |
| aBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM( "]: " ) ); |
| aBuffer.appendAscii( pMessage ); |
| aBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM( " error" ) ); |
| return aBuffer.makeStringAndClear(); |
| } |
| |
| } // namespace |
| |
| // starts parsing with actual parser ! |
| void FastSaxParser::parse() |
| { |
| const int BUFFER_SIZE = 16 * 1024; |
| Sequence< sal_Int8 > seqOut( BUFFER_SIZE ); |
| |
| Entity& rEntity = getEntity(); |
| int nRead = 0; |
| do |
| { |
| nRead = rEntity.maConverter.readAndConvert( seqOut, BUFFER_SIZE ); |
| if( nRead <= 0 ) |
| { |
| XML_Parse( rEntity.mpParser, (const char*) seqOut.getConstArray(), 0, 1 ); |
| break; |
| } |
| |
| bool bContinue = XML_Parse( rEntity.mpParser, (const char*) seqOut.getConstArray(), nRead, 0 ) != 0; |
| // callbacks used inside XML_Parse may have caught an exception |
| if( !bContinue || rEntity.maSavedException.hasValue() ) |
| { |
| // Error during parsing ! |
| XML_Error xmlE = XML_GetErrorCode( rEntity.mpParser ); |
| OUString sSystemId = mxDocumentLocator->getSystemId(); |
| sal_Int32 nLine = mxDocumentLocator->getLineNumber(); |
| |
| SAXParseException aExcept( |
| lclGetErrorMessage( xmlE, sSystemId, nLine ), |
| Reference< XInterface >(), |
| Any( &rEntity.maSavedException, getCppuType( &rEntity.maSavedException ) ), |
| mxDocumentLocator->getPublicId(), |
| mxDocumentLocator->getSystemId(), |
| mxDocumentLocator->getLineNumber(), |
| mxDocumentLocator->getColumnNumber() |
| ); |
| |
| // error handler is set, it may throw the exception |
| if( rEntity.mxErrorHandler.is() ) |
| rEntity.mxErrorHandler->fatalError( Any( aExcept ) ); |
| |
| // error handler has not thrown, but parsing cannot go on, the |
| // exception MUST be thrown |
| throw aExcept; |
| } |
| } |
| while( nRead > 0 ); |
| } |
| |
| //------------------------------------------ |
| // |
| // The C-Callbacks |
| // |
| //----------------------------------------- |
| |
| namespace { |
| |
| struct AttributeData |
| { |
| OString maPrefix; |
| OString maName; |
| OString maValue; |
| }; |
| |
| } // namespace |
| |
| void FastSaxParser::callbackStartElement( const XML_Char* pwName, const XML_Char** awAttributes ) |
| { |
| Reference< XFastContextHandler > xParentContext; |
| Entity& rEntity = getEntity(); |
| if( !rEntity.maContextStack.empty() ) |
| { |
| xParentContext = rEntity.maContextStack.top()->mxContext; |
| if( !xParentContext.is() ) |
| { |
| // we ignore current elements, so no processing needed |
| pushContext(); |
| return; |
| } |
| } |
| |
| pushContext(); |
| |
| rEntity.mxAttributes->clear(); |
| |
| // create attribute map and process namespace instructions |
| int i = 0; |
| sal_Int32 nNameLen, nPrefixLen; |
| const XML_Char *pName; |
| const XML_Char *pPrefix; |
| |
| try |
| { |
| /* #158414# Each element may define new namespaces, also for attribues. |
| First, process all namespace attributes and cache other attributes in a |
| vector. Second, process the attributes after namespaces have been |
| initialized. */ |
| ::std::vector< AttributeData > aAttribs; |
| |
| // #158414# first: get namespaces |
| for( ; awAttributes[i]; i += 2 ) |
| { |
| OSL_ASSERT( awAttributes[i+1] ); |
| |
| splitName( awAttributes[i], pPrefix, nPrefixLen, pName, nNameLen ); |
| if( nPrefixLen ) |
| { |
| if( (nPrefixLen == 5) && (strncmp( pPrefix, "xmlns", 5 ) == 0) ) |
| { |
| DefineNamespace( OString( pName, nNameLen ), awAttributes[i+1] ); |
| } |
| else |
| { |
| aAttribs.resize( aAttribs.size() + 1 ); |
| aAttribs.back().maPrefix = OString( pPrefix, nPrefixLen ); |
| aAttribs.back().maName = OString( pName, nNameLen ); |
| aAttribs.back().maValue = OString( awAttributes[i+1] ); |
| } |
| } |
| else |
| { |
| if( (nNameLen == 5) && (strcmp( pName, "xmlns" ) == 0) ) |
| { |
| // namespace of the element found |
| rEntity.maContextStack.top()->maNamespace = OUString( awAttributes[i+1], strlen( awAttributes[i+1] ), RTL_TEXTENCODING_UTF8 ); |
| } |
| else |
| { |
| aAttribs.resize( aAttribs.size() + 1 ); |
| aAttribs.back().maName = OString( pName, nNameLen ); |
| aAttribs.back().maValue = OString( awAttributes[i+1] ); |
| } |
| } |
| } |
| |
| // #158414# second: fill attribute list with other attributes |
| for( ::std::vector< AttributeData >::const_iterator aIt = aAttribs.begin(), aEnd = aAttribs.end(); aIt != aEnd; ++aIt ) |
| { |
| if( aIt->maPrefix.getLength() > 0 ) |
| { |
| sal_Int32 nAttributeToken = GetTokenWithPrefix( aIt->maPrefix, aIt->maName ); |
| if( nAttributeToken != FastToken::DONTKNOW ) |
| rEntity.mxAttributes->add( nAttributeToken, aIt->maValue ); |
| else |
| rEntity.mxAttributes->addUnknown( GetNamespaceURL( aIt->maPrefix ), aIt->maName, aIt->maValue ); |
| } |
| else |
| { |
| sal_Int32 nAttributeToken = GetToken( aIt->maName ); |
| if( nAttributeToken != FastToken::DONTKNOW ) |
| rEntity.mxAttributes->add( nAttributeToken, aIt->maValue ); |
| else |
| rEntity.mxAttributes->addUnknown( aIt->maName, aIt->maValue ); |
| } |
| } |
| |
| sal_Int32 nElementToken; |
| splitName( pwName, pPrefix, nPrefixLen, pName, nNameLen ); |
| if( nPrefixLen > 0 ) |
| nElementToken = GetTokenWithPrefix( pPrefix, nPrefixLen, pName, nNameLen ); |
| else if( rEntity.maContextStack.top()->maNamespace.getLength() > 0 ) |
| nElementToken = GetTokenWithNamespaceURL( rEntity.maContextStack.top()->maNamespace, pName, nNameLen ); |
| else |
| nElementToken = GetToken( pName ); |
| rEntity.maContextStack.top()->mnElementToken = nElementToken; |
| |
| Reference< XFastAttributeList > xAttr( rEntity.mxAttributes.get() ); |
| Reference< XFastContextHandler > xContext; |
| if( nElementToken == FastToken::DONTKNOW ) |
| { |
| if( nPrefixLen > 0 ) |
| rEntity.maContextStack.top()->maNamespace = GetNamespaceURL( pPrefix, nPrefixLen ); |
| |
| const OUString aNamespace( rEntity.maContextStack.top()->maNamespace ); |
| const OUString aElementName( pPrefix, nPrefixLen, RTL_TEXTENCODING_UTF8 ); |
| rEntity.maContextStack.top()->maElementName = aElementName; |
| |
| if( xParentContext.is() ) |
| xContext = xParentContext->createUnknownChildContext( aNamespace, aElementName, xAttr ); |
| else |
| xContext = rEntity.mxDocumentHandler->createUnknownChildContext( aNamespace, aElementName, xAttr ); |
| |
| if( xContext.is() ) |
| { |
| rEntity.maContextStack.top()->mxContext = xContext; |
| xContext->startUnknownElement( aNamespace, aElementName, xAttr ); |
| } |
| } |
| else |
| { |
| if( xParentContext.is() ) |
| xContext = xParentContext->createFastChildContext( nElementToken, xAttr ); |
| else |
| xContext = rEntity.mxDocumentHandler->createFastChildContext( nElementToken, xAttr ); |
| |
| |
| if( xContext.is() ) |
| { |
| rEntity.maContextStack.top()->mxContext = xContext; |
| xContext->startFastElement( nElementToken, xAttr ); |
| } |
| } |
| } |
| catch( Exception& e ) |
| { |
| rEntity.maSavedException <<= e; |
| } |
| } |
| |
| void FastSaxParser::callbackEndElement( const XML_Char* ) |
| { |
| Entity& rEntity = getEntity(); |
| OSL_ENSURE( !rEntity.maContextStack.empty(), "FastSaxParser::callbackEndElement - no context" ); |
| if( !rEntity.maContextStack.empty() ) |
| { |
| SaxContextImplPtr pContext = rEntity.maContextStack.top(); |
| const Reference< XFastContextHandler >& xContext( pContext->mxContext ); |
| if( xContext.is() ) try |
| { |
| sal_Int32 nElementToken = pContext->mnElementToken; |
| if( nElementToken != FastToken::DONTKNOW ) |
| xContext->endFastElement( nElementToken ); |
| else |
| xContext->endUnknownElement( pContext->maNamespace, pContext->maElementName ); |
| } |
| catch( Exception& e ) |
| { |
| rEntity.maSavedException <<= e; |
| } |
| |
| popContext(); |
| } |
| } |
| |
| |
| void FastSaxParser::callbackCharacters( const XML_Char* s, int nLen ) |
| { |
| Entity& rEntity = getEntity(); |
| const Reference< XFastContextHandler >& xContext( rEntity.maContextStack.top()->mxContext ); |
| if( xContext.is() ) try |
| { |
| xContext->characters( OUString( s, nLen, RTL_TEXTENCODING_UTF8 ) ); |
| } |
| catch( Exception& e ) |
| { |
| rEntity.maSavedException <<= e; |
| } |
| } |
| |
| int FastSaxParser::callbackExternalEntityRef( XML_Parser parser, |
| const XML_Char *context, const XML_Char * /*base*/, const XML_Char *systemId, const XML_Char *publicId ) |
| { |
| bool bOK = true; |
| InputSource source; |
| |
| Entity& rCurrEntity = getEntity(); |
| Entity aNewEntity( rCurrEntity ); |
| |
| if( rCurrEntity.mxEntityResolver.is() ) try |
| { |
| aNewEntity.maStructSource = rCurrEntity.mxEntityResolver->resolveEntity( |
| OUString( publicId, strlen( publicId ), RTL_TEXTENCODING_UTF8 ) , |
| OUString( systemId, strlen( systemId ), RTL_TEXTENCODING_UTF8 ) ); |
| } |
| catch( SAXParseException & e ) |
| { |
| rCurrEntity.maSavedException <<= e; |
| bOK = false; |
| } |
| catch( SAXException & e ) |
| { |
| rCurrEntity.maSavedException <<= SAXParseException( |
| e.Message, e.Context, e.WrappedException, |
| mxDocumentLocator->getPublicId(), |
| mxDocumentLocator->getSystemId(), |
| mxDocumentLocator->getLineNumber(), |
| mxDocumentLocator->getColumnNumber() ); |
| bOK = false; |
| } |
| |
| if( aNewEntity.maStructSource.aInputStream.is() ) |
| { |
| aNewEntity.mpParser = XML_ExternalEntityParserCreate( parser, context, 0 ); |
| if( !aNewEntity.mpParser ) |
| { |
| return false; |
| } |
| |
| aNewEntity.maConverter.setInputStream( aNewEntity.maStructSource.aInputStream ); |
| pushEntity( aNewEntity ); |
| try |
| { |
| parse(); |
| } |
| catch( SAXParseException & e ) |
| { |
| rCurrEntity.maSavedException <<= e; |
| bOK = false; |
| } |
| catch( IOException &e ) |
| { |
| SAXException aEx; |
| aEx.WrappedException <<= e; |
| rCurrEntity.maSavedException <<= aEx; |
| bOK = false; |
| } |
| catch( RuntimeException &e ) |
| { |
| SAXException aEx; |
| aEx.WrappedException <<= e; |
| rCurrEntity.maSavedException <<= aEx; |
| bOK = false; |
| } |
| |
| popEntity(); |
| XML_ParserFree( aNewEntity.mpParser ); |
| } |
| |
| return bOK; |
| } |
| |
| } // namespace sax_fastparser |