From 03d76d034e5e5e30cc8de98e103c5a6e881ec06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=BA=C5=A1=20Kukan?= Date: Tue, 8 Oct 2013 15:17:01 +0200 Subject: [PATCH] fastparser: isolate calls to XFastContextHandler in Entity's methods Unfortunately, we have to store maNamespace in two stacks. One for future parser thread to compute tokens and one for main thread calling XFastContextHandler. Now we are prepared to implement multithreading. Change-Id: I421b55afa2e9ea80142e6068c7a515d31913ba69 --- sax/source/fastparser/fastparser.cxx | 236 +++++++++++++-------------- sax/source/fastparser/fastparser.hxx | 29 +++- 2 files changed, 141 insertions(+), 124 deletions(-) diff --git a/sax/source/fastparser/fastparser.cxx b/sax/source/fastparser/fastparser.cxx index 623638a1a9dd..c67658adda93 100644 --- a/sax/source/fastparser/fastparser.cxx +++ b/sax/source/fastparser/fastparser.cxx @@ -23,7 +23,6 @@ #include #include -#include #include #include @@ -41,18 +40,15 @@ using namespace ::com::sun::star::io; namespace sax_fastparser { -// -------------------------------------------------------------------- - -struct SaxContextImpl +SaxContext::SaxContext( sal_Int32 nElementToken, const OUString& aNamespace, const OUString& aElementName ): + mnElementToken(nElementToken) { - Reference< XFastContextHandler > mxContext; - sal_Int32 mnElementToken; - OUString maNamespace; - OUString maElementName; - - SaxContextImpl() { mnElementToken = 0; } - SaxContextImpl( const SaxContextImplPtr& p ) { mnElementToken = p->mnElementToken; maNamespace = p->maNamespace; } -}; + if (nElementToken == FastToken::DONTKNOW) + { + maNamespace = aNamespace; + maElementName = aElementName; + } +} // -------------------------------------------------------------------- @@ -193,6 +189,89 @@ Entity::~Entity() { } +void Entity::startElement( sal_Int32 nElementToken, const OUString& aNamespace, + const OUString& aElementName, FastAttributeList *pAttributes ) +{ + Reference< XFastContextHandler > xParentContext; + if( !maContextStack.empty() ) + { + xParentContext = maContextStack.top().mxContext; + if (!xParentContext.is()) + { + maContextStack.push( SaxContext(nElementToken, aNamespace, aElementName) ); + return; + } + } + + maContextStack.push( SaxContext(nElementToken, aNamespace, aElementName) ); + + try + { + Reference< XFastAttributeList > xAttr( pAttributes ); + Reference< XFastContextHandler > xContext; + if( nElementToken == FastToken::DONTKNOW ) + { + if( xParentContext.is() ) + xContext = xParentContext->createUnknownChildContext( aNamespace, aElementName, xAttr ); + else if( mxDocumentHandler.is() ) + xContext = mxDocumentHandler->createUnknownChildContext( aNamespace, aElementName, xAttr ); + + if( xContext.is() ) + { + xContext->startUnknownElement( aNamespace, aElementName, xAttr ); + } + } + else + { + if( xParentContext.is() ) + xContext = xParentContext->createFastChildContext( nElementToken, xAttr ); + else if( mxDocumentHandler.is() ) + xContext = mxDocumentHandler->createFastChildContext( nElementToken, xAttr ); + + if( xContext.is() ) + { + xContext->startFastElement( nElementToken, xAttr ); + } + } + maContextStack.top().mxContext = xContext; + } + catch (const Exception& e) + { + maSavedException <<= e; + } +} + +void Entity::characters( const OUString& sChars ) +{ + const Reference< XFastContextHandler >& xContext( maContextStack.top().mxContext ); + if( xContext.is() ) try + { + xContext->characters( sChars ); + } + catch (const Exception& e) + { + maSavedException <<= e; + } +} + +void Entity::endElement() +{ + const SaxContext& aContext = maContextStack.top(); + const Reference< XFastContextHandler >& xContext( aContext.mxContext ); + if( xContext.is() ) try + { + sal_Int32 nElementToken = aContext.mnElementToken; + if( nElementToken != FastToken::DONTKNOW ) + xContext->endFastElement( nElementToken ); + else + xContext->endUnknownElement( aContext.maNamespace.get(), aContext.maElementName.get() ); + } + catch (const Exception& e) + { + maSavedException <<= e; + } + maContextStack.pop(); +} // -------------------------------------------------------------------- // FastSaxParser implementation // -------------------------------------------------------------------- @@ -213,36 +292,6 @@ FastSaxParser::~FastSaxParser() // -------------------------------------------------------------------- -void FastSaxParser::pushContext() -{ - Entity& rEntity = getEntity(); - if( rEntity.maContextStack.empty() ) - { - rEntity.maContextStack.push( SaxContextImplPtr( new SaxContextImpl ) ); - rEntity.maNamespaceCount.push(0); - DefineNamespace( OString("xml"), "http://www.w3.org/XML/1998/namespace"); - } - else - { - rEntity.maContextStack.push( SaxContextImplPtr( new SaxContextImpl( rEntity.maContextStack.top() ) ) ); - rEntity.maNamespaceCount.push( rEntity.maNamespaceCount.top() ); - } -} - -// -------------------------------------------------------------------- - -void FastSaxParser::popContext() -{ - Entity& rEntity = getEntity(); - assert(!rEntity.maContextStack.empty()); // pop without push? - if( !rEntity.maContextStack.empty() ) - rEntity.maContextStack.pop(); - if( !rEntity.maNamespaceCount.empty() ) - rEntity.maNamespaceCount.pop(); -} - -// -------------------------------------------------------------------- - void FastSaxParser::DefineNamespace( const OString& rPrefix, const sal_Char* pNamespaceURL ) { Entity& rEntity = getEntity(); @@ -727,20 +776,16 @@ struct AttributeData void FastSaxParser::callbackStartElement( const XML_Char* pwName, const XML_Char** awAttributes ) { - Reference< XFastContextHandler > xParentContext; Entity& rEntity = getEntity(); - if( !rEntity.maContextStack.empty() ) + if( rEntity.maNamespaceCount.empty() ) { - xParentContext = rEntity.maContextStack.top()->mxContext; - if( !xParentContext.is() ) - { - // we ignore current elements, so no processing needed - pushContext(); - return; - } + rEntity.maNamespaceCount.push(0); + DefineNamespace( OString("xml"), "http://www.w3.org/XML/1998/namespace"); + } + else + { + rEntity.maNamespaceCount.push( rEntity.maNamespaceCount.top() ); } - - pushContext(); rEntity.mxAttributes->clear(); @@ -749,6 +794,9 @@ void FastSaxParser::callbackStartElement( const XML_Char* pwName, const XML_Char sal_Int32 nNameLen, nPrefixLen; const XML_Char *pName; const XML_Char *pPrefix; + OUString aNamespace; + if (!rEntity.maNamespaceStack.empty()) + aNamespace = rEntity.maNamespaceStack.top(); try { @@ -783,7 +831,7 @@ void FastSaxParser::callbackStartElement( const XML_Char* pwName, const XML_Char 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 ); + aNamespace = OUString( awAttributes[i+1], strlen( awAttributes[i+1] ), RTL_TEXTENCODING_UTF8 ); } else { @@ -819,48 +867,18 @@ void FastSaxParser::callbackStartElement( const XML_Char* pwName, const XML_Char splitName( pwName, pPrefix, nPrefixLen, pName, nNameLen ); if( nPrefixLen > 0 ) nElementToken = GetTokenWithPrefix( pPrefix, nPrefixLen, pName, nNameLen ); - else if( !rEntity.maContextStack.top()->maNamespace.isEmpty() ) - nElementToken = GetTokenWithNamespaceURL( rEntity.maContextStack.top()->maNamespace, pName, nNameLen ); + else if( !aNamespace.isEmpty() ) + nElementToken = GetTokenWithNamespaceURL( aNamespace, 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 ); + aNamespace = GetNamespaceURL( pPrefix, nPrefixLen ); - const OUString aNamespace( rEntity.maContextStack.top()->maNamespace ); - const OUString aElementName( pName, nNameLen, RTL_TEXTENCODING_UTF8 ); - rEntity.maContextStack.top()->maElementName = aElementName; - - if( xParentContext.is() ) - xContext = xParentContext->createUnknownChildContext( aNamespace, aElementName, xAttr ); - else if( rEntity.mxDocumentHandler.is() ) - 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 if( rEntity.mxDocumentHandler.is() ) - xContext = rEntity.mxDocumentHandler->createFastChildContext( nElementToken, xAttr ); - - - if( xContext.is() ) - { - rEntity.maContextStack.top()->mxContext = xContext; - xContext->startFastElement( nElementToken, xAttr ); - } - } + rEntity.maNamespaceStack.push(aNamespace); + rEntity.startElement( nElementToken, aNamespace, + OUString(pName, nNameLen, RTL_TEXTENCODING_UTF8), rEntity.mxAttributes.get() ); } catch (const Exception& e) { @@ -871,41 +889,21 @@ void FastSaxParser::callbackStartElement( const XML_Char* pwName, const XML_Char void FastSaxParser::callbackEndElement( SAL_UNUSED_PARAMETER const XML_Char* ) { Entity& rEntity = getEntity(); - assert(!rEntity.maContextStack.empty()); // 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 (const Exception& e) - { - rEntity.maSavedException <<= e; - } + assert( !rEntity.maNamespaceCount.empty() ); + if( !rEntity.maNamespaceCount.empty() ) + rEntity.maNamespaceCount.pop(); - popContext(); - } + assert( !rEntity.maNamespaceStack.empty() ); + if( !rEntity.maNamespaceStack.empty() ) + rEntity.maNamespaceStack.pop(); + + rEntity.endElement(); } 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 (const Exception& e) - { - rEntity.maSavedException <<= e; - } + getEntity().characters( OUString( s, nLen, RTL_TEXTENCODING_UTF8 ) ); } void FastSaxParser::callbackEntityDecl( diff --git a/sax/source/fastparser/fastparser.hxx b/sax/source/fastparser/fastparser.hxx index aa71fb0ad4d9..51086965a8b4 100644 --- a/sax/source/fastparser/fastparser.hxx +++ b/sax/source/fastparser/fastparser.hxx @@ -22,12 +22,14 @@ #include #include -#include +#include #include +#include #include +#include +#include #include #include -#include #include #include @@ -43,9 +45,7 @@ namespace sax_fastparser { class FastLocatorImpl; struct NamespaceDefine; -struct SaxContextImpl; -typedef ::boost::shared_ptr< SaxContextImpl > SaxContextImplPtr; typedef ::boost::shared_ptr< NamespaceDefine > NamespaceDefineRef; typedef ::boost::unordered_map< OUString, sal_Int32, @@ -53,6 +53,17 @@ typedef ::boost::unordered_map< OUString, sal_Int32, // -------------------------------------------------------------------- +struct SaxContext +{ + ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastContextHandler > mxContext; + sal_Int32 mnElementToken; + boost::optional< OUString > maNamespace; + boost::optional< OUString > maElementName; + SaxContext( sal_Int32 nElementToken, const OUString& aNamespace, const OUString& aElementName ); +}; + +// -------------------------------------------------------------------- + struct ParserData { ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastDocumentHandler > mxDocumentHandler; @@ -79,13 +90,21 @@ struct Entity : public ParserData // therefore the exception must be saved somewhere. ::com::sun::star::uno::Any maSavedException; - ::std::stack< SaxContextImplPtr > maContextStack; + ::std::stack< OUString > maNamespaceStack; + /* Context for main thread consuming events. + * startElement() stores the data, which characters() and endElement() uses + */ + ::std::stack< SaxContext> maContextStack; // Determines which elements of maNamespaceDefines are valid in current context ::std::stack< sal_uInt32 > maNamespaceCount; ::std::vector< NamespaceDefineRef > maNamespaceDefines; explicit Entity( const ParserData& rData ); ~Entity(); + void startElement( sal_Int32 nElementToken, const OUString& aNamespace, + const OUString& aElementName, FastAttributeList *pAttributes ); + void characters( const OUString& sChars ); + void endElement(); }; // --------------------------------------------------------------------