[Libreoffice-commits] core.git: Branch 'feature/saxparser' - 7 commits - include/sax sax/CppunitTest_sax_parser.mk sax/Module_sax.mk sax/qa sax/source

Matúš Kukan matus.kukan at gmail.com
Tue Oct 15 13:16:27 PDT 2013


 include/sax/fastattribs.hxx          |    5 
 sax/CppunitTest_sax_parser.mk        |   43 +++++++
 sax/Module_sax.mk                    |    9 -
 sax/qa/cppunit/parser.cxx            |  108 +++++++++++++++++++
 sax/source/fastparser/fastparser.cxx |  198 ++++++++++++++++++-----------------
 sax/source/fastparser/fastparser.hxx |   44 ++++---
 sax/source/tools/fastattribs.cxx     |   73 ++++++------
 7 files changed, 324 insertions(+), 156 deletions(-)

New commits:
commit d574f3781717add908985d74d2f568effaea2d5a
Author: Matúš Kukan <matus.kukan at gmail.com>
Date:   Tue Oct 15 17:28:35 2013 +0200

    sax: add unittest for fastparser
    
    Adapt FastSaxParser so that it does not require XFastDocumentHandler.
    
    Change-Id: I7af49752dfbb4b55b8dde094fe6b762bd179be78

diff --git a/sax/CppunitTest_sax_parser.mk b/sax/CppunitTest_sax_parser.mk
new file mode 100644
index 0000000..ed2176d
--- /dev/null
+++ b/sax/CppunitTest_sax_parser.mk
@@ -0,0 +1,43 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,sax_parser))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sax_parser, \
+    sax/qa/cppunit/parser \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,sax_parser, \
+	comphelper \
+	cppu \
+	sal \
+	test \
+))
+
+$(eval $(call gb_CppunitTest_use_api,sax_parser,\
+    offapi \
+    udkapi \
+))
+
+$(eval $(call gb_CppunitTest_use_ure,sax_parser))
+
+$(eval $(call gb_CppunitTest_use_components,sax_parser,\
+	configmgr/source/configmgr \
+	framework/util/fwk \
+	i18npool/util/i18npool \
+	oox/util/oox \
+	sax/source/fastparser/fastsax \
+	sfx2/util/sfx \
+	ucb/source/core/ucb1 \
+	ucb/source/ucp/file/ucpfile1 \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,sax_parser))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sax/Module_sax.mk b/sax/Module_sax.mk
index 17c98c0..4352282 100644
--- a/sax/Module_sax.mk
+++ b/sax/Module_sax.mk
@@ -10,14 +10,15 @@
 $(eval $(call gb_Module_Module,sax))
 
 $(eval $(call gb_Module_add_targets,sax,\
-    Library_expwrap \
-    Library_fastsax \
-    Library_sax \
+	Library_expwrap \
+	Library_fastsax \
+	Library_sax \
 	StaticLibrary_sax_shared \
 ))
 
 $(eval $(call gb_Module_add_check_targets,sax,\
-    CppunitTest_sax \
+	CppunitTest_sax \
+	CppunitTest_sax_parser \
 ))
 
 # vim: set noet sw=4 ts=4:
diff --git a/sax/qa/cppunit/parser.cxx b/sax/qa/cppunit/parser.cxx
new file mode 100644
index 0000000..861c53f
--- /dev/null
+++ b/sax/qa/cppunit/parser.cxx
@@ -0,0 +1,108 @@
+/* -*- 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 <sal/config.h>
+
+#include <com/sun/star/io/Pipe.hpp>
+#include <com/sun/star/xml/sax/SAXParseException.hpp>
+#include <com/sun/star/xml/sax/XFastParser.hpp>
+#include <com/sun/star/xml/sax/XFastTokenHandler.hpp>
+
+#include <test/bootstrapfixture.hxx>
+#include <comphelper/componentcontext.hxx>
+
+using namespace css;
+using namespace css::xml::sax;
+
+namespace {
+
+class ParserTest: public test::BootstrapFixture
+{
+    InputSource maInput;
+    uno::Reference< XFastParser > mxParser;
+    uno::Reference< XFastTokenHandler > mxTokenHandler;
+    uno::Reference< XFastDocumentHandler > mxDocumentHandler;
+
+public:
+    virtual void setUp();
+    virtual void tearDown();
+
+    void parse();
+
+    CPPUNIT_TEST_SUITE(ParserTest);
+    CPPUNIT_TEST(parse);
+    CPPUNIT_TEST_SUITE_END();
+
+private:
+    uno::Reference< io::XInputStream > createStream(OString sInput);
+};
+
+void ParserTest::setUp()
+{
+    test::BootstrapFixture::setUp();
+    mxParser.set( comphelper::ComponentContext(m_xContext).createComponent(
+                "com.sun.star.xml.sax.FastParser"), uno::UNO_QUERY );
+    CPPUNIT_ASSERT_MESSAGE("No FastParser!", mxParser.is());
+    mxTokenHandler.set( comphelper::ComponentContext(m_xContext).createComponent(
+                "com.sun.star.xml.sax.FastTokenHandler"), uno::UNO_QUERY );
+    CPPUNIT_ASSERT_MESSAGE("No TokenHandler!", mxTokenHandler.is());
+    mxParser->setTokenHandler( mxTokenHandler );
+}
+
+void ParserTest::tearDown()
+{
+    test::BootstrapFixture::tearDown();
+}
+
+uno::Reference< io::XInputStream > ParserTest::createStream(OString sInput)
+{
+    uno::Reference< io::XOutputStream > xPipe( io::Pipe::create(m_xContext) );
+    uno::Reference< io::XInputStream > xInStream( xPipe, uno::UNO_QUERY );
+    uno::Sequence< sal_Int8 > aSeq( (sal_Int8*)sInput.getStr(), sInput.getLength() );
+    xPipe->writeBytes( aSeq );
+    xPipe->flush();
+    xPipe->closeOutput();
+    return xInStream;
+}
+
+void ParserTest::parse()
+{
+    maInput.aInputStream = createStream("<a>...<b />..</a>");
+    mxParser->parseStream( maInput );
+
+    maInput.aInputStream = createStream("<b></a>");
+    bool bException = false;
+    try
+    {
+        mxParser->parseStream( maInput );
+    }
+    catch (const SAXParseException &)
+    {
+        bException = true;
+    }
+    CPPUNIT_ASSERT_MESSAGE("No Exception!", bException);
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ParserTest);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sax/source/fastparser/fastparser.cxx b/sax/source/fastparser/fastparser.cxx
index a271c28..664b28b 100644
--- a/sax/source/fastparser/fastparser.cxx
+++ b/sax/source/fastparser/fastparser.cxx
@@ -246,7 +246,7 @@ void Entity::startElement( Event *pEvent )
         {
             if( xParentContext.is() )
                 xContext = xParentContext->createUnknownChildContext( aNamespace, aElementName, xAttr );
-            else
+            else if( mxDocumentHandler.is() )
                 xContext = mxDocumentHandler->createUnknownChildContext( aNamespace, aElementName, xAttr );
 
             if( xContext.is() )
@@ -258,7 +258,7 @@ void Entity::startElement( Event *pEvent )
         {
             if( xParentContext.is() )
                 xContext = xParentContext->createFastChildContext( nElementToken, xAttr );
-            else
+            else if( mxDocumentHandler.is() )
                 xContext = mxDocumentHandler->createFastChildContext( nElementToken, xAttr );
 
             if( xContext.is() )
commit 7036afe099a387ebcce686378140e68447657dec
Author: Matúš Kukan <matus.kukan at gmail.com>
Date:   Tue Oct 15 14:43:24 2013 +0200

    fastparser: don't create temporary Events; use references to event list
    
    Change-Id: I1e12fbeeb90d6020d0566d05fc0318082e1da5fc

diff --git a/sax/source/fastparser/fastparser.cxx b/sax/source/fastparser/fastparser.cxx
index 0e90dcb..a271c28 100644
--- a/sax/source/fastparser/fastparser.cxx
+++ b/sax/source/fastparser/fastparser.cxx
@@ -76,7 +76,8 @@ private:
         }
         catch (const SAXParseException& e)
         {
-            mpParser->produce(Event( CallbackType::EXCEPTION ));
+            mpParser->getEntity().getEvent( CallbackType::EXCEPTION );
+            mpParser->produce( CallbackType::EXCEPTION );
         }
     }
 };
@@ -187,28 +188,6 @@ OUString SAL_CALL FastLocatorImpl::getSystemId(void) throw (RuntimeException)
 
 // --------------------------------------------------------------------
 
-Event::Event(const CallbackType& t): maType(t)
-{}
-
-Event::Event(const CallbackType& t, const OUString& sChars): Event(t)
-{
-    msChars = sChars;
-}
-
-Event::Event(const CallbackType& t, sal_Int32 nElementToken, const OUString& aNamespace,
-        const OUString& aElementName, FastAttributeList *pAttributes): Event(t)
-{
-    mnElementToken = nElementToken;
-    maNamespace = aNamespace;
-    maElementName = aElementName;
-    mpAttributes = rtl::Reference< FastAttributeList >(pAttributes);
-}
-
-Event::~Event()
-{}
-
-// --------------------------------------------------------------------
-
 ParserData::ParserData()
 {}
 
@@ -243,9 +222,9 @@ Entity::~Entity()
 
 void Entity::startElement( Event *pEvent )
 {
-    const sal_Int32& nElementToken = pEvent->mnElementToken.get();
-    const OUString& aNamespace = pEvent->maNamespace.get();
-    const OUString& aElementName = pEvent->maElementName.get();
+    const sal_Int32& nElementToken = pEvent->mnElementToken;
+    const OUString& aNamespace = pEvent->msNamespace;
+    const OUString& aElementName = pEvent->msElementName;
     Reference< XFastContextHandler > xParentContext;
     if( !maContextStack.empty() )
     {
@@ -261,7 +240,7 @@ void Entity::startElement( Event *pEvent )
 
     try
     {
-        Reference< XFastAttributeList > xAttr( pEvent->mpAttributes.get().get() );
+        Reference< XFastAttributeList > xAttr( pEvent->mxAttributes.get() );
         Reference< XFastContextHandler > xContext;
         if( nElementToken == FastToken::DONTKNOW )
         {
@@ -337,17 +316,26 @@ EventList* Entity::getEventList()
             mpProducedEvents = maUsedEvents.front();
             maUsedEvents.pop();
             aGuard.clear(); // unlock
-            mpProducedEvents->clear();
+            mnProducedEventsSize = 0;
         }
         if (!mpProducedEvents)
         {
             mpProducedEvents = new EventList();
-            mpProducedEvents->reserve(mnEventListSize);
+            mpProducedEvents->resize(mnEventListSize);
+            mnProducedEventsSize = 0;
         }
     }
     return mpProducedEvents;
 }
 
+Event& Entity::getEvent( CallbackType aType )
+{
+    EventList* pEventList = getEventList();
+    Event& rEvent = (*pEventList)[mnProducedEventsSize++];
+    rEvent.maType = aType;
+    return rEvent;
+}
+
 // --------------------------------------------------------------------
 // FastSaxParser implementation
 // --------------------------------------------------------------------
@@ -604,6 +592,7 @@ void FastSaxParser::parseStream( const InputSource& maStructSource) throw (SAXEx
                     done = true;
 
                 aGuard.reset(); // lock
+                rEntity.maUsedEvents.push(pEventList);
             }
         } while (!done);
         xParser->join();
@@ -792,14 +781,12 @@ void FastSaxParser::deleteUsedEvents()
     }
 }
 
-void FastSaxParser::produce(const Event& aEvent)
+void FastSaxParser::produce( CallbackType aType )
 {
     Entity& rEntity = getEntity();
-    EventList* pEventList = rEntity.getEventList();
-    pEventList->push_back( aEvent );
-    if (aEvent.maType == CallbackType::DONE ||
-        aEvent.maType == CallbackType::EXCEPTION ||
-        pEventList->size() == rEntity.mnEventListSize)
+    if (aType == CallbackType::DONE ||
+        aType == CallbackType::EXCEPTION ||
+        rEntity.mnProducedEventsSize == rEntity.mnEventListSize)
     {
         osl::ResettableMutexGuard aGuard(rEntity.maEventProtector);
 
@@ -811,7 +798,7 @@ void FastSaxParser::produce(const Event& aEvent)
             aGuard.reset(); // lock
         }
 
-        rEntity.maPendingEvents.push(pEventList);
+        rEntity.maPendingEvents.push(rEntity.mpProducedEvents);
         rEntity.mpProducedEvents = 0;
 
         aGuard.clear(); // unlock
@@ -823,7 +810,6 @@ void FastSaxParser::produce(const Event& aEvent)
 bool FastSaxParser::consume(EventList *pEventList)
 {
     Entity& rEntity = getEntity();
-    bool bIsParserFinished = false;
     for (EventList::iterator aEventIt = pEventList->begin();
             aEventIt != pEventList->end(); ++aEventIt)
     {
@@ -836,13 +822,12 @@ bool FastSaxParser::consume(EventList *pEventList)
                 rEntity.endElement();
                 break;
             case CallbackType::CHARACTERS:
-                rEntity.characters( (*aEventIt).msChars.get() );
+                rEntity.characters( (*aEventIt).msChars );
                 break;
             case CallbackType::DONE:
-                bIsParserFinished = true;
-                assert(aEventIt+1 == pEventList->end());
-                break;
+                return false;
             case CallbackType::EXCEPTION:
+            {
                 assert( rEntity.maSavedException.hasValue() );
                 // Error during parsing !
                 XML_Error xmlE = XML_GetErrorCode( rEntity.mpParser );
@@ -863,10 +848,13 @@ bool FastSaxParser::consume(EventList *pEventList)
                     rEntity.mxErrorHandler->fatalError( Any( aExcept ) );
 
                 throw aExcept;
+            }
+            default:
+                assert(false);
+                return false;
         }
     }
-    rEntity.maUsedEvents.push(pEventList);
-    return !bIsParserFinished;
+    return true;
 }
 
 // starts parsing with actual parser !
@@ -916,7 +904,8 @@ void FastSaxParser::parse()
         }
     }
     while( nRead > 0 );
-    produce(Event( CallbackType::DONE ));
+    rEntity.getEvent( CallbackType::DONE );
+    produce( CallbackType::DONE );
 }
 
 //------------------------------------------
@@ -939,15 +928,20 @@ void FastSaxParser::callbackStartElement( const XML_Char* pwName, const XML_Char
     }
 
     // create attribute map and process namespace instructions
+    Event& rEvent = getEntity().getEvent( CallbackType::START_ELEMENT );
+    if (rEvent.mxAttributes.is())
+        rEvent.mxAttributes->clear();
+    else
+        rEvent.mxAttributes.set( new FastAttributeList( rEntity.mxTokenHandler ) );
+
     sal_Int32 nNameLen, nPrefixLen;
     const XML_Char *pName;
     const XML_Char *pPrefix;
-    OUString sNamespace;
+
     sal_Int32 nNamespaceToken = FastToken::DONTKNOW;
-    FastAttributeList *pAttributes = new FastAttributeList( rEntity.mxTokenHandler );
     if (!rEntity.maNamespaceStack.empty())
     {
-        sNamespace = rEntity.maNamespaceStack.top().msName;
+        rEvent.msNamespace = rEntity.maNamespaceStack.top().msName;
         nNamespaceToken = rEntity.maNamespaceStack.top().mnToken;
     }
 
@@ -976,8 +970,8 @@ void FastSaxParser::callbackStartElement( const XML_Char* pwName, const XML_Char
                 if( (nNameLen == 5) && (strcmp( pName, "xmlns" ) == 0) )
                 {
                     // default namespace is the attribute value
-                    sNamespace = OUString( awAttributes[i+1], strlen( awAttributes[i+1] ), RTL_TEXTENCODING_UTF8 );
-                    nNamespaceToken = GetNamespaceToken( sNamespace );
+                    rEvent.msNamespace = OUString( awAttributes[i+1], strlen( awAttributes[i+1] ), RTL_TEXTENCODING_UTF8 );
+                    nNamespaceToken = GetNamespaceToken( rEvent.msNamespace );
                 }
             }
         }
@@ -992,9 +986,9 @@ void FastSaxParser::callbackStartElement( const XML_Char* pwName, const XML_Char
                 {
                     sal_Int32 nAttributeToken = GetTokenWithPrefix( pPrefix, nPrefixLen, pName, nNameLen );
                     if( nAttributeToken != FastToken::DONTKNOW )
-                        pAttributes->add( nAttributeToken, OString(awAttributes[i+1]) );
+                        rEvent.mxAttributes->add( nAttributeToken, OString(awAttributes[i+1]) );
                     else
-                        pAttributes->addUnknown( GetNamespaceURL( pPrefix, nPrefixLen ),
+                        rEvent.mxAttributes->addUnknown( GetNamespaceURL( pPrefix, nPrefixLen ),
                                 OString(pName, nNameLen), OString(awAttributes[i+1]) );
                 }
             }
@@ -1004,32 +998,31 @@ void FastSaxParser::callbackStartElement( const XML_Char* pwName, const XML_Char
                 {
                     sal_Int32 nAttributeToken = GetToken( pName, nNameLen );
                     if( nAttributeToken != FastToken::DONTKNOW )
-                        pAttributes->add( nAttributeToken, OString(awAttributes[i+1]) );
+                        rEvent.mxAttributes->add( nAttributeToken, OString(awAttributes[i+1]) );
                     else
-                        pAttributes->addUnknown( OString(pName, nNameLen), OString(awAttributes[i+1]) );
+                        rEvent.mxAttributes->addUnknown( OString(pName, nNameLen), OString(awAttributes[i+1]) );
                 }
             }
         }
 
-        sal_Int32 nElementToken;
         splitName( pwName, pPrefix, nPrefixLen, pName, nNameLen );
         if( nPrefixLen > 0 )
-            nElementToken = GetTokenWithPrefix( pPrefix, nPrefixLen, pName, nNameLen );
-        else if( !sNamespace.isEmpty() )
-            nElementToken = GetTokenWithContextNamespace( nNamespaceToken, pName, nNameLen );
+            rEvent.mnElementToken = GetTokenWithPrefix( pPrefix, nPrefixLen, pName, nNameLen );
+        else if( !rEvent.msNamespace.isEmpty() )
+            rEvent.mnElementToken = GetTokenWithContextNamespace( nNamespaceToken, pName, nNameLen );
         else
-            nElementToken = GetToken( pName );
+            rEvent.mnElementToken = GetToken( pName );
 
-        if( nElementToken == FastToken::DONTKNOW )
+        if( rEvent.mnElementToken == FastToken::DONTKNOW )
             if( nPrefixLen > 0 )
             {
-                sNamespace = GetNamespaceURL( pPrefix, nPrefixLen );
-                nNamespaceToken = GetNamespaceToken( sNamespace );
+                rEvent.msNamespace = GetNamespaceURL( pPrefix, nPrefixLen );
+                nNamespaceToken = GetNamespaceToken( rEvent.msNamespace );
             }
 
-        rEntity.maNamespaceStack.push( NameWithToken(sNamespace, nNamespaceToken) );
-        produce(Event( CallbackType::START_ELEMENT, nElementToken, sNamespace,
-                    OUString(pName, nNameLen, RTL_TEXTENCODING_UTF8), pAttributes ));
+        rEntity.maNamespaceStack.push( NameWithToken(rEvent.msNamespace, nNamespaceToken) );
+        rEvent.msElementName = OUString(pName, nNameLen, RTL_TEXTENCODING_UTF8);
+        produce( CallbackType::START_ELEMENT );
     }
     catch (const Exception& e)
     {
@@ -1048,13 +1041,16 @@ void FastSaxParser::callbackEndElement( SAL_UNUSED_PARAMETER const XML_Char* )
     if( !rEntity.maNamespaceStack.empty() )
         rEntity.maNamespaceStack.pop();
 
-    produce(Event( CallbackType::END_ELEMENT ));
+    rEntity.getEvent( CallbackType::END_ELEMENT );
+    produce( CallbackType::END_ELEMENT );
 }
 
 
 void FastSaxParser::callbackCharacters( const XML_Char* s, int nLen )
 {
-    produce(Event( CallbackType::CHARACTERS, OUString(s, nLen, RTL_TEXTENCODING_UTF8) ));
+    Event& rEvent = getEntity().getEvent( CallbackType::CHARACTERS );
+    rEvent.msChars = OUString(s, nLen, RTL_TEXTENCODING_UTF8);
+    produce( CallbackType::CHARACTERS );
 }
 
 void FastSaxParser::callbackEntityDecl(
diff --git a/sax/source/fastparser/fastparser.hxx b/sax/source/fastparser/fastparser.hxx
index 135cf6c..28ce7e2 100644
--- a/sax/source/fastparser/fastparser.hxx
+++ b/sax/source/fastparser/fastparser.hxx
@@ -56,7 +56,7 @@ typedef ::boost::unordered_map< OUString, sal_Int32,
 
 typedef std::vector<Event> EventList;
 
-enum CallbackType { START_ELEMENT, END_ELEMENT, CHARACTERS, DONE, EXCEPTION };
+enum CallbackType { INVALID, START_ELEMENT, END_ELEMENT, CHARACTERS, DONE, EXCEPTION };
 
 struct NameWithToken
 {
@@ -67,17 +67,12 @@ struct NameWithToken
 };
 
 struct Event {
-    boost::optional< OUString > msChars;
-    boost::optional< sal_Int32 > mnElementToken;
-    boost::optional< OUString > maNamespace;
-    boost::optional< OUString > maElementName;
-    boost::optional< rtl::Reference< FastAttributeList > > mpAttributes;
+    OUString msChars;
+    sal_Int32 mnElementToken;
+    OUString msNamespace;
+    OUString msElementName;
+    rtl::Reference< FastAttributeList > mxAttributes;
     CallbackType maType;
-    Event(const CallbackType& t);
-    Event(const CallbackType& t, const OUString& sChars);
-    Event(const CallbackType& t, sal_Int32 nElementToken, const OUString& aNamespace,
-            const OUString& aElementName, FastAttributeList *pAttributes);
-    ~Event();
 };
 
 // --------------------------------------------------------------------
@@ -112,6 +107,8 @@ struct Entity : public ParserData
 {
     // unique for each Entity instance:
 
+    // Number of valid events in mpProducedEvents:
+    size_t mnProducedEventsSize;
     EventList *mpProducedEvents;
     std::queue< EventList * > maPendingEvents;
     std::queue< EventList * > maUsedEvents;
@@ -150,6 +147,7 @@ struct Entity : public ParserData
     void characters( const OUString& sChars );
     void endElement();
     EventList* getEventList();
+    Event& getEvent( CallbackType aType );
 };
 
 // --------------------------------------------------------------------
@@ -193,7 +191,7 @@ public:
     inline void popEntity()                         { maEntities.pop(); }
     Entity& getEntity()                             { return maEntities.top(); }
     void parse();
-    void produce( const Event& );
+    void produce( CallbackType aType );
 
 private:
     bool consume(EventList *);
commit d94c70368db5d5dfa9ecce58ebf55f4fbc7ee237
Author: Matúš Kukan <matus.kukan at gmail.com>
Date:   Tue Oct 15 11:39:04 2013 +0200

    fastparser: fix leak by storing rtl::Reference instead of pointer
    
    Change-Id: I003dc48fed9029c9af430d4d2d361425d351ff54

diff --git a/sax/source/fastparser/fastparser.cxx b/sax/source/fastparser/fastparser.cxx
index 2484d22..0e90dcb 100644
--- a/sax/source/fastparser/fastparser.cxx
+++ b/sax/source/fastparser/fastparser.cxx
@@ -201,7 +201,7 @@ Event::Event(const CallbackType& t, sal_Int32 nElementToken, const OUString& aNa
     mnElementToken = nElementToken;
     maNamespace = aNamespace;
     maElementName = aElementName;
-    mpAttributes = pAttributes;
+    mpAttributes = rtl::Reference< FastAttributeList >(pAttributes);
 }
 
 Event::~Event()
@@ -241,9 +241,11 @@ Entity::~Entity()
 {
 }
 
-void Entity::startElement( sal_Int32 nElementToken, const OUString& aNamespace,
-            const OUString& aElementName, FastAttributeList *pAttributes )
+void Entity::startElement( Event *pEvent )
 {
+    const sal_Int32& nElementToken = pEvent->mnElementToken.get();
+    const OUString& aNamespace = pEvent->maNamespace.get();
+    const OUString& aElementName = pEvent->maElementName.get();
     Reference< XFastContextHandler > xParentContext;
     if( !maContextStack.empty() )
     {
@@ -259,7 +261,7 @@ void Entity::startElement( sal_Int32 nElementToken, const OUString& aNamespace,
 
     try
     {
-        Reference< XFastAttributeList > xAttr( pAttributes );
+        Reference< XFastAttributeList > xAttr( pEvent->mpAttributes.get().get() );
         Reference< XFastContextHandler > xContext;
         if( nElementToken == FastToken::DONTKNOW )
         {
@@ -822,14 +824,13 @@ bool FastSaxParser::consume(EventList *pEventList)
 {
     Entity& rEntity = getEntity();
     bool bIsParserFinished = false;
-    for (EventList::const_iterator aEventIt = pEventList->begin();
+    for (EventList::iterator aEventIt = pEventList->begin();
             aEventIt != pEventList->end(); ++aEventIt)
     {
         switch ((*aEventIt).maType)
         {
             case CallbackType::START_ELEMENT:
-                rEntity.startElement( (*aEventIt).mnElementToken.get(), (*aEventIt).maNamespace.get(),
-                        (*aEventIt).maElementName.get(), (*aEventIt).mpAttributes.get() );
+                rEntity.startElement( &(*aEventIt) );
                 break;
             case CallbackType::END_ELEMENT:
                 rEntity.endElement();
diff --git a/sax/source/fastparser/fastparser.hxx b/sax/source/fastparser/fastparser.hxx
index 1e154b8..135cf6c 100644
--- a/sax/source/fastparser/fastparser.hxx
+++ b/sax/source/fastparser/fastparser.hxx
@@ -71,7 +71,7 @@ struct Event {
     boost::optional< sal_Int32 > mnElementToken;
     boost::optional< OUString > maNamespace;
     boost::optional< OUString > maElementName;
-    boost::optional< FastAttributeList * > mpAttributes;
+    boost::optional< rtl::Reference< FastAttributeList > > mpAttributes;
     CallbackType maType;
     Event(const CallbackType& t);
     Event(const CallbackType& t, const OUString& sChars);
@@ -146,8 +146,7 @@ struct Entity : public ParserData
     explicit Entity( const ParserData& rData );
     Entity( const Entity& rEntity );
     ~Entity();
-    void startElement( sal_Int32 nElementToken, const OUString& aNamespace,
-            const OUString& aElementName, FastAttributeList *pAttributes );
+    void startElement( Event *pEvent );
     void characters( const OUString& sChars );
     void endElement();
     EventList* getEventList();
commit 14b69701f0da5a6133a7e174c6328416512341a3
Author: Matúš Kukan <matus.kukan at gmail.com>
Date:   Tue Oct 15 10:32:55 2013 +0200

    fastparser:  re-use event lists if possible
    
    Change-Id: I53800abaca51d42d7d44a98fb271de7df7f90f58

diff --git a/sax/source/fastparser/fastparser.cxx b/sax/source/fastparser/fastparser.cxx
index deee49e..2484d22 100644
--- a/sax/source/fastparser/fastparser.cxx
+++ b/sax/source/fastparser/fastparser.cxx
@@ -324,6 +324,28 @@ void Entity::endElement()
     }
     maContextStack.pop();
 }
+
+EventList* Entity::getEventList()
+{
+    if (!mpProducedEvents)
+    {
+        osl::ResettableMutexGuard aGuard(maEventProtector);
+        if (!maUsedEvents.empty())
+        {
+            mpProducedEvents = maUsedEvents.front();
+            maUsedEvents.pop();
+            aGuard.clear(); // unlock
+            mpProducedEvents->clear();
+        }
+        if (!mpProducedEvents)
+        {
+            mpProducedEvents = new EventList();
+            mpProducedEvents->reserve(mnEventListSize);
+        }
+    }
+    return mpProducedEvents;
+}
+
 // --------------------------------------------------------------------
 // FastSaxParser implementation
 // --------------------------------------------------------------------
@@ -771,15 +793,11 @@ void FastSaxParser::deleteUsedEvents()
 void FastSaxParser::produce(const Event& aEvent)
 {
     Entity& rEntity = getEntity();
-    if (!rEntity.mpProducedEvents)
-    {
-        rEntity.mpProducedEvents = new EventList();
-        rEntity.mpProducedEvents->reserve(rEntity.mnEventListSize);
-    }
-    rEntity.mpProducedEvents->push_back( aEvent );
+    EventList* pEventList = rEntity.getEventList();
+    pEventList->push_back( aEvent );
     if (aEvent.maType == CallbackType::DONE ||
         aEvent.maType == CallbackType::EXCEPTION ||
-        rEntity.mpProducedEvents->size() == rEntity.mnEventListSize)
+        pEventList->size() == rEntity.mnEventListSize)
     {
         osl::ResettableMutexGuard aGuard(rEntity.maEventProtector);
 
@@ -791,14 +809,12 @@ void FastSaxParser::produce(const Event& aEvent)
             aGuard.reset(); // lock
         }
 
-        rEntity.maPendingEvents.push(rEntity.mpProducedEvents);
+        rEntity.maPendingEvents.push(pEventList);
         rEntity.mpProducedEvents = 0;
 
         aGuard.clear(); // unlock
 
         rEntity.maConsumeResume.set();
-
-        deleteUsedEvents();
     }
 }
 
diff --git a/sax/source/fastparser/fastparser.hxx b/sax/source/fastparser/fastparser.hxx
index 8859c46..1e154b8 100644
--- a/sax/source/fastparser/fastparser.hxx
+++ b/sax/source/fastparser/fastparser.hxx
@@ -150,6 +150,7 @@ struct Entity : public ParserData
             const OUString& aElementName, FastAttributeList *pAttributes );
     void characters( const OUString& sChars );
     void endElement();
+    EventList* getEventList();
 };
 
 // --------------------------------------------------------------------
commit 51137d7e4a63dc4be1e1f01873d74f7e541b4251
Author: Matúš Kukan <matus.kukan at gmail.com>
Date:   Tue Oct 15 09:29:27 2013 +0200

    FastAttributeList: use vectors instead of map; the size is small
    
    Change-Id: If0ea36155d8ab3f5c91c2aafd6932fabeadadd41

diff --git a/include/sax/fastattribs.hxx b/include/sax/fastattribs.hxx
index f31be4b..88e9d61 100644
--- a/include/sax/fastattribs.hxx
+++ b/include/sax/fastattribs.hxx
@@ -47,7 +47,6 @@ struct UnknownAttribute
     void FillAttribute( ::com::sun::star::xml::Attribute* pAttrib ) const;
 };
 
-typedef std::map< sal_Int32, OString > FastAttributeMap;
 typedef std::vector< UnknownAttribute > UnknownAttributeList;
 
 class SAX_DLLPUBLIC FastAttributeList : public ::cppu::WeakImplHelper1< ::com::sun::star::xml::sax::XFastAttributeList >
@@ -71,9 +70,9 @@ public:
     virtual ::com::sun::star::uno::Sequence< ::com::sun::star::xml::FastAttribute > SAL_CALL getFastAttributes() throw (::com::sun::star::uno::RuntimeException);
 
 private:
-    FastAttributeMap maAttributes;
+    std::vector< sal_Int32 > maAttributeTokens;
+    std::vector< OString > maAttributeValues;
     UnknownAttributeList maUnknownAttributes;
-    FastAttributeMap::iterator maLastIter;
     ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler > mxTokenHandler;
 
 };
diff --git a/sax/source/tools/fastattribs.cxx b/sax/source/tools/fastattribs.cxx
index bb348a4..b25ff08 100644
--- a/sax/source/tools/fastattribs.cxx
+++ b/sax/source/tools/fastattribs.cxx
@@ -50,7 +50,6 @@ void UnknownAttribute::FillAttribute( Attribute* pAttrib ) const
 FastAttributeList::FastAttributeList( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler >& xTokenHandler )
 : mxTokenHandler( xTokenHandler )
 {
-    maLastIter = maAttributes.end();
 }
 
 FastAttributeList::~FastAttributeList()
@@ -59,14 +58,15 @@ FastAttributeList::~FastAttributeList()
 
 void FastAttributeList::clear()
 {
-    maAttributes.clear();
+    maAttributeTokens.clear();
+    maAttributeValues.clear();
     maUnknownAttributes.clear();
-    maLastIter = maAttributes.end();
 }
 
 void FastAttributeList::add( sal_Int32 nToken, const OString& rValue )
 {
-    maAttributes[nToken] = rValue;
+    maAttributeTokens.push_back( nToken );
+    maAttributeValues.push_back( rValue );
 }
 
 void FastAttributeList::addUnknown( const OUString& rNamespaceURL, const OString& rName, const OString& rValue )
@@ -82,55 +82,53 @@ void FastAttributeList::addUnknown( const OString& rName, const OString& rValue
 // XFastAttributeList
 sal_Bool FastAttributeList::hasAttribute( ::sal_Int32 Token ) throw (RuntimeException)
 {
-    maLastIter = maAttributes.find( Token );
-    return ( maLastIter != maAttributes.end() ) ? sal_True : sal_False;
+    for (size_t i = 0; i < maAttributeTokens.size(); ++i)
+        if (maAttributeTokens[i] == Token)
+            return sal_True;
+
+    return sal_False;
 }
 
 sal_Int32 FastAttributeList::getValueToken( ::sal_Int32 Token ) throw (SAXException, RuntimeException)
 {
-    if( ( maLastIter == maAttributes.end() ) || ( ( *maLastIter ).first != Token ) )
-        maLastIter = maAttributes.find( Token );
-
-    if( maLastIter == maAttributes.end() )
-        throw SAXException();
+    for (size_t i = 0; i < maAttributeTokens.size(); ++i)
+        if (maAttributeTokens[i] == Token)
+        {
+            Sequence< sal_Int8 > aSeq( (sal_Int8*) maAttributeValues[i].getStr(), maAttributeValues[i].getLength() );
+            return mxTokenHandler->getTokenFromUTF8( aSeq );
+        }
 
-    Sequence< sal_Int8 > aSeq( (sal_Int8*)(*maLastIter).second.getStr(), (*maLastIter).second.getLength() ) ;
-    return mxTokenHandler->getTokenFromUTF8( aSeq );
+    throw SAXException();
 }
 
 sal_Int32 FastAttributeList::getOptionalValueToken( ::sal_Int32 Token, ::sal_Int32 Default ) throw (RuntimeException)
 {
-    if( ( maLastIter == maAttributes.end() ) || ( ( *maLastIter ).first != Token ) )
-        maLastIter = maAttributes.find( Token );
-
-    if( maLastIter == maAttributes.end() )
-        return Default;
+    for (size_t i = 0; i < maAttributeTokens.size(); ++i)
+        if (maAttributeTokens[i] == Token)
+        {
+            Sequence< sal_Int8 > aSeq( (sal_Int8*) maAttributeValues[i].getStr(), maAttributeValues[i].getLength() );
+            return mxTokenHandler->getTokenFromUTF8( aSeq );
+        }
 
-    Sequence< sal_Int8 > aSeq( (sal_Int8*)(*maLastIter).second.getStr(), (*maLastIter).second.getLength() ) ;
-    return mxTokenHandler->getTokenFromUTF8( aSeq );
+    return Default;
 }
 
 OUString FastAttributeList::getValue( ::sal_Int32 Token ) throw (SAXException, RuntimeException)
 {
-    if( ( maLastIter == maAttributes.end() ) || ( ( *maLastIter ).first != Token ) )
-        maLastIter = maAttributes.find( Token );
+    for (size_t i = 0; i < maAttributeTokens.size(); ++i)
+        if (maAttributeTokens[i] == Token)
+            return OStringToOUString( maAttributeValues[i], RTL_TEXTENCODING_UTF8 );
 
-    if( maLastIter == maAttributes.end() )
-        throw SAXException();
-
-    return OStringToOUString( (*maLastIter).second, RTL_TEXTENCODING_UTF8 );
+    throw SAXException();
 }
 
 OUString FastAttributeList::getOptionalValue( ::sal_Int32 Token ) throw (RuntimeException)
 {
-    if( ( maLastIter == maAttributes.end() ) || ( ( *maLastIter ).first != Token ) )
-        maLastIter = maAttributes.find( Token );
-
-    OUString aRet;
-    if( maLastIter != maAttributes.end() )
-        aRet = OStringToOUString( (*maLastIter).second, RTL_TEXTENCODING_UTF8 );
+    for (size_t i = 0; i < maAttributeTokens.size(); ++i)
+        if (maAttributeTokens[i] == Token)
+            return OStringToOUString( maAttributeValues[i], RTL_TEXTENCODING_UTF8 );
 
-    return aRet;
+    return OUString();
 }
 Sequence< Attribute > FastAttributeList::getUnknownAttributes(  ) throw (RuntimeException)
 {
@@ -142,13 +140,12 @@ Sequence< Attribute > FastAttributeList::getUnknownAttributes(  ) throw (Runtime
 }
 Sequence< FastAttribute > FastAttributeList::getFastAttributes(  ) throw (RuntimeException)
 {
-    Sequence< FastAttribute > aSeq( maAttributes.size() );
+    Sequence< FastAttribute > aSeq( maAttributeTokens.size() );
     FastAttribute* pAttr = aSeq.getArray();
-    FastAttributeMap::iterator fastAttrIter = maAttributes.begin();
-    for(; fastAttrIter != maAttributes.end(); ++fastAttrIter )
+    for (size_t i = 0; i < maAttributeTokens.size(); ++i)
     {
-        pAttr->Token = fastAttrIter->first;
-        pAttr->Value = OStringToOUString( fastAttrIter->second, RTL_TEXTENCODING_UTF8 );
+        pAttr->Token = maAttributeTokens[i];
+        pAttr->Value = OStringToOUString( maAttributeValues[i], RTL_TEXTENCODING_UTF8 );
         pAttr++;
     }
     return aSeq;
commit a606a6b91955f5da17c0e6c88365e484f2e2b0cf
Author: Matúš Kukan <matus.kukan at gmail.com>
Date:   Mon Oct 14 21:47:54 2013 +0200

    fastparser: don't use pointers in context stack
    
    Change-Id: Id45fd2edd6186b58062bb77e894b7d8618b723e8

diff --git a/sax/source/fastparser/fastparser.cxx b/sax/source/fastparser/fastparser.cxx
index 9c0b176..deee49e 100644
--- a/sax/source/fastparser/fastparser.cxx
+++ b/sax/source/fastparser/fastparser.cxx
@@ -24,7 +24,6 @@
 #include <salhelper/thread.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>
 
@@ -42,25 +41,15 @@ using namespace ::com::sun::star::io;
 
 namespace sax_fastparser {
 
-// --------------------------------------------------------------------
-
-struct SaxContextImpl
-{
-    Reference< XFastContextHandler >    mxContext;
-    sal_Int32                           mnElementToken;
-    boost::optional< OUString >         maNamespace;
-    boost::optional< OUString >         maElementName;
-
-    SaxContextImpl( sal_Int32 nElementToken, const OUString& aNamespace, const OUString& aElementName ):
+SaxContext::SaxContext( sal_Int32 nElementToken, const OUString& aNamespace, const OUString& aElementName ):
         mnElementToken(nElementToken)
+{
+    if (nElementToken == FastToken::DONTKNOW)
     {
-        if (nElementToken == FastToken::DONTKNOW)
-        {
-            maNamespace = aNamespace;
-            maElementName = aElementName;
-        }
+        maNamespace = aNamespace;
+        maElementName = aElementName;
     }
-};
+}
 
 // --------------------------------------------------------------------
 
@@ -258,15 +247,15 @@ void Entity::startElement( sal_Int32 nElementToken, const OUString& aNamespace,
     Reference< XFastContextHandler > xParentContext;
     if( !maContextStack.empty() )
     {
-        xParentContext = maContextStack.top()->mxContext;
+        xParentContext = maContextStack.top().mxContext;
         if (!xParentContext.is())
         {
-            maContextStack.push( new SaxContextImpl(nElementToken, aNamespace, aElementName) );
+            maContextStack.push( SaxContext(nElementToken, aNamespace, aElementName) );
             return;
         }
     }
 
-    maContextStack.push( new SaxContextImpl(nElementToken, aNamespace, aElementName) );
+    maContextStack.push( SaxContext(nElementToken, aNamespace, aElementName) );
 
     try
     {
@@ -296,7 +285,7 @@ void Entity::startElement( sal_Int32 nElementToken, const OUString& aNamespace,
                 xContext->startFastElement( nElementToken, xAttr );
             }
         }
-        maContextStack.top()->mxContext = xContext;
+        maContextStack.top().mxContext = xContext;
     }
     catch (const Exception& e)
     {
@@ -306,7 +295,7 @@ void Entity::startElement( sal_Int32 nElementToken, const OUString& aNamespace,
 
 void Entity::characters( const OUString& sChars )
 {
-    const Reference< XFastContextHandler >& xContext( maContextStack.top()->mxContext );
+    const Reference< XFastContextHandler >& xContext( maContextStack.top().mxContext );
     if( xContext.is() ) try
     {
         xContext->characters( sChars );
@@ -319,21 +308,20 @@ void Entity::characters( const OUString& sChars )
 
 void Entity::endElement()
 {
-    SaxContextImpl* pContext = maContextStack.top();
-    const Reference< XFastContextHandler >& xContext( pContext->mxContext );
+    const SaxContext& aContext = maContextStack.top();
+    const Reference< XFastContextHandler >& xContext( aContext.mxContext );
     if( xContext.is() ) try
     {
-        sal_Int32 nElementToken = pContext->mnElementToken;
+        sal_Int32 nElementToken = aContext.mnElementToken;
         if( nElementToken != FastToken::DONTKNOW )
             xContext->endFastElement( nElementToken );
         else
-            xContext->endUnknownElement( pContext->maNamespace.get(), pContext->maElementName.get() );
+            xContext->endUnknownElement( aContext.maNamespace.get(), aContext.maElementName.get() );
     }
     catch (const Exception& e)
     {
         maSavedException <<= e;
     }
-    delete pContext;
     maContextStack.pop();
 }
 // --------------------------------------------------------------------
diff --git a/sax/source/fastparser/fastparser.hxx b/sax/source/fastparser/fastparser.hxx
index 184f4ef..8859c46 100644
--- a/sax/source/fastparser/fastparser.hxx
+++ b/sax/source/fastparser/fastparser.hxx
@@ -28,9 +28,10 @@
 #include <boost/unordered_map.hpp>
 #include <osl/conditn.hxx>
 #include <rtl/ref.hxx>
+#include <com/sun/star/xml/sax/XFastContextHandler.hpp>
+#include <com/sun/star/xml/sax/XFastDocumentHandler.hpp>
 #include <com/sun/star/xml/sax/XFastParser.hpp>
 #include <com/sun/star/xml/sax/XFastTokenHandler.hpp>
-#include <com/sun/star/xml/sax/XFastDocumentHandler.hpp>
 #include <com/sun/star/lang/XServiceInfo.hpp>
 #include <cppuhelper/implbase2.hxx>
 
@@ -47,7 +48,6 @@ namespace sax_fastparser {
 struct Event;
 class FastLocatorImpl;
 struct NamespaceDefine;
-struct SaxContextImpl;
 
 typedef ::boost::shared_ptr< NamespaceDefine > NamespaceDefineRef;
 
@@ -82,6 +82,17 @@ struct Event {
 
 // --------------------------------------------------------------------
 
+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;
@@ -124,7 +135,10 @@ struct Entity : public ParserData
     ::com::sun::star::uno::Any              maSavedException;
 
     ::std::stack< NameWithToken >           maNamespaceStack;
-    ::std::stack< SaxContextImpl* >         maContextStack;
+    /* 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;
commit e1571394d6dfd28b27c3a00f48dcb1d8f20496b9
Author: Matúš Kukan <matus.kukan at gmail.com>
Date:   Mon Oct 14 18:23:36 2013 +0200

    fastparser: use boost::optional in SaxContextImpl
    
    Change-Id: Ia6c797b105348afcc0c426ba2abe3fa0a3c452fe

diff --git a/sax/source/fastparser/fastparser.cxx b/sax/source/fastparser/fastparser.cxx
index 8941b0e..9c0b176 100644
--- a/sax/source/fastparser/fastparser.cxx
+++ b/sax/source/fastparser/fastparser.cxx
@@ -47,12 +47,19 @@ namespace sax_fastparser {
 struct SaxContextImpl
 {
     Reference< XFastContextHandler >    mxContext;
-    sal_Int32       mnElementToken;
-    OUString        maNamespace;
-    OUString        maElementName;
+    sal_Int32                           mnElementToken;
+    boost::optional< OUString >         maNamespace;
+    boost::optional< OUString >         maElementName;
 
     SaxContextImpl( sal_Int32 nElementToken, const OUString& aNamespace, const OUString& aElementName ):
-        mnElementToken(nElementToken), maNamespace(aNamespace), maElementName(aElementName) {}
+        mnElementToken(nElementToken)
+    {
+        if (nElementToken == FastToken::DONTKNOW)
+        {
+            maNamespace = aNamespace;
+            maElementName = aElementName;
+        }
+    }
 };
 
 // --------------------------------------------------------------------
@@ -320,7 +327,7 @@ void Entity::endElement()
         if( nElementToken != FastToken::DONTKNOW )
             xContext->endFastElement( nElementToken );
         else
-            xContext->endUnknownElement( pContext->maNamespace, pContext->maElementName );
+            xContext->endUnknownElement( pContext->maNamespace.get(), pContext->maElementName.get() );
     }
     catch (const Exception& e)
     {


More information about the Libreoffice-commits mailing list