diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2014-11-20 13:42:16 +0100 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2014-11-20 18:43:44 +0100 |
commit | 0df9ac47dfa287249e77bb8f6a5555324a94a48d (patch) | |
tree | 5b1a2eded3f710821fcb9f2ef5c3c5a9e6e0b141 /sax | |
parent | 06d90253c2890d437063aae263a1f9a5f9280ad8 (diff) |
make FastSaxParser provide the whole content in one characters() call
SAX interface is not required to provide the whole node content in one
characters() call (e.g. if there's an entity that needs decoding). However
it's easier to consumers to assume this (e.g. writerfilter's
DomainMapper::lcl_utext() handles datecontrol that way), and expat apparently
never used this. However this can happen with libxml2, so ensure such consumers
still work.
Change-Id: Ib564f372fbea8451f84553a6d49a07d091a950e9
Diffstat (limited to 'sax')
-rw-r--r-- | sax/source/fastparser/fastparser.cxx | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/sax/source/fastparser/fastparser.cxx b/sax/source/fastparser/fastparser.cxx index 38a4bbb750b4..e1d22d215f78 100644 --- a/sax/source/fastparser/fastparser.cxx +++ b/sax/source/fastparser/fastparser.cxx @@ -237,6 +237,7 @@ public: private: bool consume(EventList *); void deleteUsedEvents(); + void sendPendingCharacters(); sal_Int32 GetToken( const xmlChar* pName, sal_Int32 nameLen ); sal_Int32 GetTokenWithPrefix( const xmlChar* pPrefix, int prefixLen, const xmlChar* pName, int nameLen ) throw (::com::sun::star::xml::sax::SAXException); @@ -257,6 +258,7 @@ private: Entity *mpTop; /// std::stack::top() is amazingly slow => cache this. ::std::stack< Entity > maEntities; /// Entity stack for each call of parseStream(). + OUString pendingCharacters; /// Data from characters() callback that needs to be sent. }; } // namespace sax_fastparser @@ -1048,6 +1050,8 @@ void FastSaxParserImpl::parse() void FastSaxParserImpl::callbackStartElement(const xmlChar *localName , const xmlChar* prefix, const xmlChar* URI, int numNamespaces, const xmlChar** namespaces, int numAttributes, int /*defaultedAttributes*/, const xmlChar **attributes) { + if( !pendingCharacters.isEmpty()) + sendPendingCharacters(); Entity& rEntity = getEntity(); if( rEntity.maNamespaceCount.empty() ) { @@ -1154,6 +1158,8 @@ void FastSaxParserImpl::callbackStartElement(const xmlChar *localName , const xm void FastSaxParserImpl::callbackEndElement( const xmlChar*, const xmlChar*, const xmlChar* ) { + if( !pendingCharacters.isEmpty()) + sendPendingCharacters(); Entity& rEntity = getEntity(); assert( !rEntity.maNamespaceCount.empty() ); if( !rEntity.maNamespaceCount.empty() ) @@ -1172,9 +1178,20 @@ void FastSaxParserImpl::callbackEndElement( const xmlChar*, const xmlChar*, cons void FastSaxParserImpl::callbackCharacters( const xmlChar* s, int nLen ) { + // SAX interface allows that the characters callback splits content of one XML node + // (e.g. because there's an entity that needs decoding), however for consumers it's + // simpler FastSaxParser's character callback provides the whole string at once, + // so merge data from possible multiple calls and send them at once (before the element + // ends or another one starts). + pendingCharacters += OUString( XML_CAST( s ), nLen, RTL_TEXTENCODING_UTF8 ); +} + +void FastSaxParserImpl::sendPendingCharacters() +{ Entity& rEntity = getEntity(); Event& rEvent = rEntity.getEvent( CHARACTERS ); - rEvent.msChars = OUString( XML_CAST( s ), nLen, RTL_TEXTENCODING_UTF8); + rEvent.msChars = pendingCharacters; + pendingCharacters.clear(); if (rEntity.mbEnableThreads) produce(); else |