/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: fastparser.cxx,v $ * * $Revision: 1.2 $ * * last change: $Author: obo $ $Date: 2008-01-10 12:52:30 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. * * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2005 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ************************************************************************/ //#include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fastattribs.hxx" #include "xml2utf.hxx" #ifdef SYSTEM_EXPAT #include #else #include "expat/xmlparse.h" #endif using ::rtl::OUString; using ::rtl::OString; 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::registry; using namespace ::com::sun::star::xml::sax; //using namespace ::com::sun::star::util; using namespace ::com::sun::star::io; namespace sax_fastparser { // -------------------------------------------------------------------- struct SaxContextImpl; typedef boost::shared_ptr< SaxContextImpl > SaxContextImplPtr; // -------------------------------------------------------------------- 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; } }; // -------------------------------------------------------------------- // Entity binds all information neede for a single file struct Entity { InputSource maStructSource; XML_Parser mpParser; sax_expatwrap::XMLFile2UTFConverter maConverter; }; // -------------------------------------------------------------------- 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 ) {} }; typedef ::std::hash_map< ::rtl::OUString, sal_Int32, ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > NamespaceMap; // -------------------------------------------------------------------- // 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 // -------------------------------------------------------------------- #define IMPLEMENTATION_NAME "com.sun.star.comp.extensions.xml.sax.FastParser" #define SERVICE_NAME "com.sun.star.xml.sax.FastParser" // This class implements the external Parser interface class FastSaxParser : public WeakImplHelper2< XFastParser, XServiceInfo > { public: FastSaxParser(); ~FastSaxParser(); // The implementation details static Sequence< OUString > getSupportedServiceNames_Static(void); static OUString getImplementationName_Static(); // XFastParser virtual void SAL_CALL parseStream( const InputSource& aInputSource ) throw (SAXException, IOException, RuntimeException); virtual void SAL_CALL setFastDocumentHandler( const Reference< XFastDocumentHandler >& Handler ) throw (RuntimeException); virtual void SAL_CALL setTokenHandler( const Reference< XFastTokenHandler >& Handler ) throw (RuntimeException); virtual void SAL_CALL registerNamespace( const OUString& NamespaceURL, sal_Int32 NamespaceToken ) throw (IllegalArgumentException, RuntimeException); virtual void SAL_CALL setErrorHandler( const Reference< XErrorHandler >& Handler ) throw (RuntimeException); virtual void SAL_CALL setEntityResolver( const Reference< XEntityResolver >& Resolver ) throw (RuntimeException); virtual void SAL_CALL setLocale( const Locale& Locale ) throw (RuntimeException); // XServiceInfo virtual OUString SAL_CALL getImplementationName( ) throw (RuntimeException); virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw (RuntimeException); virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) throw (RuntimeException); public: // 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 ); int static callbackExternalEntityRef( XML_Parser parser, const XML_Char *openEntityNames, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId); public: void pushEntity( const struct Entity &entity ) { vecEntity.push_back( entity ); } void popEntity() { vecEntity.pop_back( ); } struct Entity &getEntity() { return vecEntity.back(); } private: void parse(); sal_Int32 GetToken( const sal_Char* pToken, sal_Int32 nTokenLen = 0 ); sal_Int32 GetTokenWithPrefix( const sal_Char*pPrefix, int nPrefixLen, const sal_Char* pName, int nNameLen ) throw (SAXException); OUString GetNamespaceURL( const sal_Char*pPrefix, int nPrefixLen ) throw (SAXException); sal_Int32 GetNamespaceToken( const OUString& rNamespaceURL ); sal_Int32 GetTokenWithNamespaceURL( const OUString& rNamespaceURL, const sal_Char* pName, int nNameLen ); void DefineNamespace( const OString& rPrefix, const sal_Char* pNamespaceURL ); sal_Int32 CreateCustomToken( const sal_Char* pToken, int len = 0 ); void pushContext(); void popContext(); void splitName( const XML_Char *pwName, const XML_Char *&rpPrefix, sal_Int32 &rPrefixLen, const XML_Char *&rpName, sal_Int32 &rNameLen ); private: Mutex maMutex; Reference< XFastDocumentHandler > mxDocumentHandler; Reference< XFastTokenHandler > mxTokenHandler; Reference< XErrorHandler > mxErrorHandler; Reference< XEntityResolver > mxEntityResolver; rtl::Reference < FastLocatorImpl > mxDocumentLocator; rtl::Reference < FastAttributeList > mxAttributes; // External entity stack vector vecEntity; // Exception cannot be thrown through the C-XmlParser (possible resource leaks), // therefor the maSavedException must be saved somewhere. Any maSavedException; sal_Bool mbExceptionWasThrown; Locale maLocale; std::stack< SaxContextImplPtr > maContextStack; std::vector< boost::shared_ptr< NamespaceDefine > > maNamespaceDefines; NamespaceMap maNamespaceMap; }; //-------------------------------------- // the extern interface //--------------------------------------- Reference< XInterface > SAL_CALL FastSaxParser_CreateInstance( const Reference< XMultiServiceFactory > & ) throw(Exception) { FastSaxParser *p = new FastSaxParser; return Reference< XInterface > ( (OWeakObject * ) p ); } Sequence< OUString > FastSaxParser::getSupportedServiceNames_Static(void) { Sequence aRet(1); aRet.getArray()[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(SERVICE_NAME) ); return aRet; } //--------------------------------------------- // the implementation part //--------------------------------------------- extern "C" { static void call_callbackStartElement(void *userData, const XML_Char *name , const XML_Char **atts) { FastSaxParser::callbackStartElement(userData,name,atts); } static void call_callbackEndElement(void *userData, const XML_Char *name) { FastSaxParser::callbackEndElement(userData,name); } static void call_callbackCharacters( void *userData , const XML_Char *s , int nLen ) { FastSaxParser::callbackCharacters(userData,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) { return FastSaxParser::callbackExternalEntityRef(parser,openEntityNames,base,systemId,publicId); } } // -------------------------------------------------------------------- // 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; } // -------------------------------------------------------------------- // FastSaxParser implementation // -------------------------------------------------------------------- FastSaxParser::FastSaxParser( ) { mxDocumentLocator.set( new FastLocatorImpl( this ) ); // 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 ) ); mbExceptionWasThrown = sal_False; } // -------------------------------------------------------------------- FastSaxParser::~FastSaxParser() { if( mxDocumentLocator.is() ) mxDocumentLocator->dispose(); } // -------------------------------------------------------------------- void FastSaxParser::pushContext() { bool bRootContext = false; SaxContextImplPtr p; if( maContextStack.empty() ) { p.reset( new SaxContextImpl() ); bRootContext = true; } else { p.reset( new SaxContextImpl( maContextStack.top() ) ); } maContextStack.push( p ); if( bRootContext ) DefineNamespace( OString("xml"), "http://www.w3.org/XML/1998/namespace"); } // -------------------------------------------------------------------- void FastSaxParser::popContext() { OSL_ENSURE( !maContextStack.empty(), "sax::FastSaxParser::popContext(), pop without push?" ); if( !maContextStack.empty() ) maContextStack.pop(); } // -------------------------------------------------------------------- void FastSaxParser::DefineNamespace( const OString& rPrefix, const sal_Char* pNamespaceURL ) { OSL_ENSURE( !maContextStack.empty(), "sax::FastSaxParser::DefineNamespace(), I need a context!" ); if( !maContextStack.empty() ) { sal_uInt32 nOffset = maContextStack.top()->mnNamespaceCount++; if( maNamespaceDefines.size() <= nOffset ) maNamespaceDefines.resize( maNamespaceDefines.size() + 64 ); const OUString aNamespaceURL( pNamespaceURL, strlen( pNamespaceURL ), RTL_TEXTENCODING_UTF8 ); maNamespaceDefines[nOffset].reset( new NamespaceDefine( rPrefix, GetNamespaceToken( aNamespaceURL ), aNamespaceURL ) ); } } // -------------------------------------------------------------------- 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 mxTokenHandler->getTokenFromUTF8( aSeq ); } // -------------------------------------------------------------------- sal_Int32 FastSaxParser::GetTokenWithPrefix( const sal_Char*pPrefix, int nPrefixLen, const sal_Char* pName, int nNameLen ) throw (SAXException) { sal_Int32 nNamespaceToken = FastToken::DONTKNOW; sal_uInt32 nNamespace = maContextStack.top()->mnNamespaceCount; while( nNamespace-- ) { const OString& rPrefix( maNamespaceDefines[nNamespace]->maPrefix ); if( (rPrefix.getLength() == nPrefixLen) && (strncmp( rPrefix.getStr(), pPrefix, nPrefixLen ) == 0 ) ) { nNamespaceToken = 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 sal_Char*pPrefix, int nPrefixLen ) throw(SAXException) { if( pPrefix && !maContextStack.empty() ) { sal_uInt32 nNamespace = maContextStack.top()->mnNamespaceCount; while( nNamespace-- ) { const OString& rPrefix( maNamespaceDefines[nNamespace]->maPrefix ); if( (rPrefix.getLength() == nPrefixLen) && (strncmp( rPrefix.getStr(), pPrefix, nPrefixLen ) == 0 ) ) { return 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 ); struct Entity entity; entity.maStructSource = maStructSource; if( ! entity.maStructSource.aInputStream.is() ) { throw SAXException( OUString::createFromAscii( "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::createFromAscii( "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); maSavedException.clear(); pushEntity( entity ); try { // start the document if( mxDocumentHandler.is() ) { Reference< XLocator > xLoc( mxDocumentLocator.get() ); mxDocumentHandler->setDocumentLocator( xLoc ); mxDocumentHandler->startDocument(); } parse(); // finish document if( mxDocumentHandler.is() ) { 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) { mxDocumentHandler = Handler; } void SAL_CALL FastSaxParser::setTokenHandler( const Reference< XFastTokenHandler >& Handler ) throw (RuntimeException) { mxTokenHandler = Handler; mxAttributes.set( new FastAttributeList( mxTokenHandler ) ); } 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) { mxErrorHandler = Handler; } void FastSaxParser::setEntityResolver(const Reference < XEntityResolver > & Resolver) throw (RuntimeException) { mxEntityResolver = Resolver; } void FastSaxParser::setLocale( const Locale & Locale ) throw (RuntimeException) { maLocale = Locale; } OUString FastSaxParser::getImplementationName_Static() { return OUString::createFromAscii( IMPLEMENTATION_NAME ); } // XServiceInfo OUString FastSaxParser::getImplementationName() throw (RuntimeException) { return OUString::createFromAscii( 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 seq(1); seq.getArray()[0] = OUString::createFromAscii( SERVICE_NAME ); return seq; } /*--------------------------------------- * * Helper functions and classes * *-------------------------------------------*/ OUString getErrorMessage( XML_Error xmlE, OUString sSystemId , sal_Int32 nLine ) { OUString Message; if( XML_ERROR_NONE == xmlE ) { Message = OUString::createFromAscii( "No" ); } else if( XML_ERROR_NO_MEMORY == xmlE ) { Message = OUString::createFromAscii( "no memory" ); } else if( XML_ERROR_SYNTAX == xmlE ) { Message = OUString::createFromAscii( "syntax" ); } else if( XML_ERROR_NO_ELEMENTS == xmlE ) { Message = OUString::createFromAscii( "no elements" ); } else if( XML_ERROR_INVALID_TOKEN == xmlE ) { Message = OUString::createFromAscii( "invalid token" ); } else if( XML_ERROR_UNCLOSED_TOKEN == xmlE ) { Message = OUString::createFromAscii( "unclosed token" ); } else if( XML_ERROR_PARTIAL_CHAR == xmlE ) { Message = OUString::createFromAscii( "partial char" ); } else if( XML_ERROR_TAG_MISMATCH == xmlE ) { Message = OUString::createFromAscii( "tag mismatch" ); } else if( XML_ERROR_DUPLICATE_ATTRIBUTE == xmlE ) { Message = OUString::createFromAscii( "duplicate attribute" ); } else if( XML_ERROR_JUNK_AFTER_DOC_ELEMENT == xmlE ) { Message = OUString::createFromAscii( "junk after doc element" ); } else if( XML_ERROR_PARAM_ENTITY_REF == xmlE ) { Message = OUString::createFromAscii( "parameter entity reference" ); } else if( XML_ERROR_UNDEFINED_ENTITY == xmlE ) { Message = OUString::createFromAscii( "undefined entity" ); } else if( XML_ERROR_RECURSIVE_ENTITY_REF == xmlE ) { Message = OUString::createFromAscii( "recursive entity reference" ); } else if( XML_ERROR_ASYNC_ENTITY == xmlE ) { Message = OUString::createFromAscii( "async entity" ); } else if( XML_ERROR_BAD_CHAR_REF == xmlE ) { Message = OUString::createFromAscii( "bad char reference" ); } else if( XML_ERROR_BINARY_ENTITY_REF == xmlE ) { Message = OUString::createFromAscii( "binary entity reference" ); } else if( XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF == xmlE ) { Message = OUString::createFromAscii( "attribute external entity reference" ); } else if( XML_ERROR_MISPLACED_XML_PI == xmlE ) { Message = OUString::createFromAscii( "misplaced xml processing instruction" ); } else if( XML_ERROR_UNKNOWN_ENCODING == xmlE ) { Message = OUString::createFromAscii( "unknown encoding" ); } else if( XML_ERROR_INCORRECT_ENCODING == xmlE ) { Message = OUString::createFromAscii( "incorrect encoding" ); } else if( XML_ERROR_UNCLOSED_CDATA_SECTION == xmlE ) { Message = OUString::createFromAscii( "unclosed cdata section" ); } else if( XML_ERROR_EXTERNAL_ENTITY_HANDLING == xmlE ) { Message = OUString::createFromAscii( "external entity reference" ); } else if( XML_ERROR_NOT_STANDALONE == xmlE ) { Message = OUString::createFromAscii( "not standalone" ); } OUString str = OUString::createFromAscii( "[" ); str += sSystemId; str += OUString::createFromAscii( " line " ); str += OUString::valueOf( nLine ); str += OUString::createFromAscii( "]: " ); str += Message; str += OUString::createFromAscii( "error" ); return str; } // starts parsing with actual parser ! void FastSaxParser::parse( ) { const int nBufSize = 16*1024; int nRead = nBufSize; Sequence< sal_Int8 > seqOut(nBufSize); while( nRead ) { nRead = getEntity().maConverter.readAndConvert( seqOut, nBufSize ); if( ! nRead ) { XML_Parse( getEntity().mpParser, ( const char * ) seqOut.getArray(), 0 , 1 ); break; } sal_Bool bContinue = ( XML_Parse( getEntity().mpParser, (const char *) seqOut.getArray(), nRead, 0 ) != 0 ); if( !bContinue || mbExceptionWasThrown ) { // Error during parsing ! XML_Error xmlE = XML_GetErrorCode( getEntity().mpParser ); OUString sSystemId = mxDocumentLocator->getSystemId(); sal_Int32 nLine = mxDocumentLocator->getLineNumber(); SAXParseException aExcept( getErrorMessage(xmlE , sSystemId, nLine) , Reference< XInterface >(), Any( &maSavedException , getCppuType( &maSavedException) ), mxDocumentLocator->getPublicId(), mxDocumentLocator->getSystemId(), mxDocumentLocator->getLineNumber(), mxDocumentLocator->getColumnNumber() ); if( mxErrorHandler.is() ) { // error handler is set, so the handler may throw the maSavedException mxErrorHandler->fatalError( Any( aExcept ) ); } // Error handler has not thrown an maSavedException, but parsing cannot go on, // so an maSavedException MUST be thrown. throw aExcept; } } } //------------------------------------------ // // The C-Callbacks // //----------------------------------------- void FastSaxParser::callbackStartElement( void *pvThis, const XML_Char *pwName, const XML_Char **awAttributes ) { FastSaxParser *pThis = (FastSaxParser*)pvThis; Reference< XFastContextHandler > xParentContext; if( !pThis->maContextStack.empty() ) { xParentContext = pThis->maContextStack.top()->mxContext; if( !xParentContext.is() ) { // we ignore current elements, so no processing needed pThis->pushContext(); return; } } pThis->pushContext(); pThis->mxAttributes->clear(); // create attribute map and process namespace instructions int i = 0; sal_Int32 nNameLen, nPrefixLen; const XML_Char *pName; const XML_Char *pPrefix; for( ; awAttributes[i]; i += 2 ) { OSL_ASSERT( awAttributes[i+1] ); pThis->splitName( awAttributes[i], pPrefix, nPrefixLen, pName, nNameLen ); if( nPrefixLen ) { if( (nPrefixLen == 5) && (strncmp( pPrefix, "xmlns", 5 ) == 0) ) { pThis->DefineNamespace( OString( pName, nNameLen ), awAttributes[i+1] ); } else { const sal_Int32 nAttributeToken = pThis->GetTokenWithPrefix( pPrefix, nPrefixLen, pName, nNameLen ); if( nAttributeToken != FastToken::DONTKNOW ) { pThis->mxAttributes->add( nAttributeToken, OString( awAttributes[i+1] ) ); } else { pThis->mxAttributes->addUnknown( pThis->GetNamespaceURL( pPrefix, nPrefixLen ), OString( pName, nNameLen ), OString( awAttributes[i+1] ) ); } } } else { if( (nNameLen == 5) && (strcmp( pName, "xmlns" ) == 0) ) { // namespace of the element found pThis->maContextStack.top()->maNamespace = OUString( awAttributes[i+1], strlen( awAttributes[i+1] ), RTL_TEXTENCODING_UTF8 ); } else { const sal_Int32 nAttributeToken = pThis->GetToken( pName, nNameLen ); if( nAttributeToken != FastToken::DONTKNOW ) { pThis->mxAttributes->add( nAttributeToken, OString( awAttributes[i+1] ) ); } else { pThis->mxAttributes->addUnknown( OString( pName, nNameLen ), OString( awAttributes[i+1] ) ); } } } } sal_Int32 nElementToken; pThis->splitName( pwName, pPrefix, nPrefixLen, pName, nNameLen ); if( nPrefixLen ) { nElementToken = pThis->GetTokenWithPrefix( pPrefix, nPrefixLen, pName, nNameLen ); } else if( pThis->maContextStack.top()->maNamespace.getLength() ) { nElementToken = pThis->GetTokenWithNamespaceURL( pThis->maContextStack.top()->maNamespace, pName, nNameLen ); } else { nElementToken = pThis->GetToken( pName ); } pThis->maContextStack.top()->mnElementToken = nElementToken; try { Reference< XFastAttributeList > xAttr( pThis->mxAttributes.get() ); Reference< XFastContextHandler > xContext; if( nElementToken == FastToken::DONTKNOW ) { if( nPrefixLen ) { pThis->maContextStack.top()->maNamespace = pThis->GetNamespaceURL( pPrefix, nPrefixLen ); } const OUString aNamespace( pThis->maContextStack.top()->maNamespace ); const OUString aElementName( pPrefix, nPrefixLen, RTL_TEXTENCODING_UTF8 ); pThis->maContextStack.top()->maElementName = aElementName; if( xParentContext.is() ) xContext = xParentContext->createUnknownChildContext( aNamespace, aElementName, xAttr ); else xContext = pThis->mxDocumentHandler->createUnknownChildContext( aNamespace, aElementName, xAttr ); if( xContext.is() ) { pThis->maContextStack.top()->mxContext = xContext; xContext->startUnknownElement( aNamespace, aElementName, xAttr ); } } else { if( xParentContext.is() ) xContext = xParentContext->createFastChildContext( nElementToken, xAttr ); else xContext = pThis->mxDocumentHandler->createFastChildContext( nElementToken, xAttr ); if( xContext.is() ) { pThis->maContextStack.top()->mxContext = xContext; xContext->startFastElement( nElementToken, xAttr ); } } } catch( Exception& e ) { pThis->maSavedException <<= e; } } void FastSaxParser::callbackEndElement( void *pvThis , const XML_Char * ) { FastSaxParser *pThis = (FastSaxParser*)pvThis; if( !pThis->maContextStack.empty() ) { SaxContextImplPtr pContext( pThis->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 ) { pThis->maSavedException <<= e; } pThis->popContext(); } else { OSL_ENSURE( false, "no context on sax::FastSaxParser::callbackEndElement() ??? "); } } void FastSaxParser::callbackCharacters( void *pvThis , const XML_Char *s , int nLen ) { FastSaxParser *pThis = (FastSaxParser*)pvThis; const Reference< XFastContextHandler >& xContext( pThis->maContextStack.top()->mxContext ); if( xContext.is() ) try { xContext->characters( OUString( s, nLen, RTL_TEXTENCODING_UTF8 ) ); } catch( Exception& e ) { pThis->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; FastSaxParser *pImpl = ((FastSaxParser*)XML_GetUserData( parser )); struct Entity entity; if( pImpl->mxEntityResolver.is() ) { try { entity.maStructSource = pImpl->mxEntityResolver->resolveEntity( OUString( publicId, strlen( publicId ), RTL_TEXTENCODING_UTF8 ) , OUString( systemId, strlen( systemId ), RTL_TEXTENCODING_UTF8 ) ); } catch( SAXParseException & e ) { pImpl->maSavedException <<= e; bOK = false; } catch( SAXException & e ) { pImpl->maSavedException <<= SAXParseException( e.Message , e.Context , e.WrappedException , pImpl->mxDocumentLocator->getPublicId(), pImpl->mxDocumentLocator->getSystemId(), pImpl->mxDocumentLocator->getLineNumber(), pImpl->mxDocumentLocator->getColumnNumber() ); bOK = false; } } if( entity.maStructSource.aInputStream.is() ) { entity.mpParser = XML_ExternalEntityParserCreate( parser , context, 0 ); if( ! entity.mpParser ) { return false; } entity.maConverter.setInputStream( entity.maStructSource.aInputStream ); pImpl->pushEntity( entity ); try { pImpl->parse(); } catch( SAXParseException & e ) { pImpl->maSavedException <<= e; bOK = false; } catch( IOException &e ) { SAXException aEx; aEx.WrappedException <<= e; pImpl->maSavedException <<= aEx; bOK = false; } catch( RuntimeException &e ) { SAXException aEx; aEx.WrappedException <<= e; pImpl->maSavedException <<= aEx; bOK = false; } pImpl->popEntity(); XML_ParserFree( entity.mpParser ); } return bOK; } } using namespace sax_fastparser; extern "C" { void SAL_CALL component_getImplementationEnvironment( const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) { *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; } sal_Bool SAL_CALL component_writeInfo( void * /*pServiceManager*/, void * pRegistryKey ) { if (pRegistryKey) { try { Reference< XRegistryKey > xKey( reinterpret_cast< XRegistryKey * >( pRegistryKey ) ); Reference< XRegistryKey > xNewKey( xKey->createKey( OUString::createFromAscii( "/" IMPLEMENTATION_NAME "/UNO/SERVICES" ) ) ); xNewKey->createKey( OUString::createFromAscii( SERVICE_NAME ) ); return sal_True; } catch (InvalidRegistryException &) { OSL_ENSURE( sal_False, "### InvalidRegistryException!" ); } } return sal_False; } void * SAL_CALL component_getFactory( const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) { void * pRet = 0; if (pServiceManager ) { Reference< XSingleServiceFactory > xRet; Reference< XMultiServiceFactory > xSMgr( reinterpret_cast< XMultiServiceFactory * > ( pServiceManager ) ); OUString aImplementationName( OUString::createFromAscii( pImplName ) ); if (aImplementationName == OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ) ) { xRet = createSingleFactory( xSMgr, aImplementationName, FastSaxParser_CreateInstance, FastSaxParser::getSupportedServiceNames_Static() ); } if (xRet.is()) { xRet->acquire(); pRet = xRet.get(); } } return pRet; } }