Hi We currently use 2 XML libraries in our C/C++ code, expat and libxml2. This is unnecessary, one of them can be removed, and I propose we remove expat.
expat is a small library that only does SAX parsing, and lacks DOM, lacks XSLT, lacks schema validation or any more advanced features we use. By comparison, libxml2 is probably the most complete open-source XML library in the world for C, with endless features, many users, stable API, no mandatory dependencies, portable, highly standards compliant and compatible with other XML libraries, performs well (https://xmlbench.sourceforge.net/results/benchmark200910/index.html), is a requirement for libxslt, is permissively licensed, takes security seriously (the maintainer made money by fixing its security bugs in Google's bug bounties), actively developed, documented, nice readable source code, and it's generally of very high quality. We generally don't like unnecessary dependencies, and expat has been difficult to upgrade to newer versions due to compiler issues. Since expat only implements a small subset of libxml2's features, could we replace it with libxml2? Where is expat used? The output of "grep expat */prj/build.lst" gives us these modules: lucene openssl sax shell tools lucene and openssl don't really require expat. Removing expat from their build.lst and stopping the expat/ module from building still gets lucene and openssl to build successfully, so clearly their dependency on expat was always unnecessary. As of commit 461facd3d94599cc708db50510b7e42483407720 they no longer depend on expat. tools probably also has an unnecessary dependency on expat, but this is harder to prove as tools -> i18pool -> sax -> expat, so let's revisit this later. Only the sax and shell modules really use expat. In sax, it is used to implement the com.sun.star.xml.sax.Parser UNO service (com.sun.star.comp.extensions.xml.sax.ParserExpat implementation name), which is used fairly widely throughout AOO, including for loading OpenDocument files (sax -> svx -> xmloff), but all the expat usage is contained in a single file: sax/source/expatwrap/sax_expat.cxx. In shell, it is used to implement a SAX parser internal to that module, which is then consumed by several libraries, including source/unix/sysshell which deals with the recently used file list in $HOME/.recently-used. -------------------------------- Porting sax to libxml2 -------------------------------- Patching the sax module to use libxml2 instead of expat was successful enough to get AOO to build, run and load documents, even though it's still incomplete. Most of the SAX callbacks are compatible between expat and libxml2, and converting those was easy. String types had to be changed, and sometimes the parameter list has to be reordered, or expat-only parameters removed. CDATA is reported with a single event in libxml2, which needed conversion to startCDATA + characters + endCDATA events on our UNO callbacks. Unfortunately expat's XML_SetExternalEntityRefHandler() works quite differently on libxml2, and has been commented out for now while I try to understand what external entities are and how you generally load them. Also expat's XML_SetDefaultHandlerExpand() is not yet implemented and I am not sure what to do there. One gotcha was that when there are no attributes on an element, libxml2 calls the startElement() callback with NULL attributes, while expat called it with attributes to a 1 element char** array containing NULL. This was crashing i18npool's saxparser during the build, in SaxExpatParser_Impl::callbackStartElement() during the conversion of attributes to its attribute list. Luckily it was easy to fix. The code for sax_expat.cxx has become quite a bit shorter, because libxml2 always uses UTF-8 unlike expat which can be built with UTF-16 or UTF-8, so the XmlNChar2OUString() and XmlChar2OUString() functions have been removed. Also the getErrorMessage() function no longer has to have a list of hardcoded error codes with our error message for each, as libxml2's xmlCtxtGetLastError() returns the official error message. Also the sax module uses the SAX1 API. libxml2 supports both SAX1 and SAX2, but SAX1 is optional, and will be disabled if LIBXML_SAX1_ENABLED is undefined in libxml2's include/libxml/xmlversion.h. Currently it's hardcoded to 1, so it should always be defined, but when we use the system libxml2, we don't know that for sure. For now, I've added a check for LIBXML_SAX1_ENABLED and preprocessor #error if missing. It's also possible for the sax module to convert SAX2 callbacks to SAX1 on the UNO side, but that's inefficient (eg. we'd have to concatenate namespace + ":" + localname, which the consuming code will later just split up again). Ideally we would make a XDocumentHandler2 UNO interface based on SAX2, and upstream UNO consumers would use that, so we could use SAX2 throughout AOO. This is more of a long-term plan though, for now SAX1 should be fine. Even with these issues, it works perfectly, building and running and loading many documents. I am sure libxml2 is being used to load documents instead of expat, because a debugger breakpoint on expat's XML_Parse() doesn't get triggered. -------------------------------- Porting shell to libxml2 -------------------------------- I haven't started this yet (but you can ;). It seems easier, fewer expat APIs are used, and since the module is internal and we control both the library and its consumers, it might even be possible to use SAX2 throughout, instead of the custom parsing of tag names into namespaces that it currently does. -------------- In closing -------------- They say "release early, release often" is what made open-source software good, so I am attaching a patch with what I've done so far. Please review, test, and if you can, help implement XML_SetExternalEntityRefHandler() and XML_SetDefaultHandlerExpand(), and port the shell module. It would also be good to have benchmarks of how long it takes to load a large document with expat vs libxml2. Thank you Damjan
diff --git a/main/sax/Library_expwrap.mk b/main/sax/Library_expwrap.mk index 8f19828077..b9135963b5 100644 --- a/main/sax/Library_expwrap.mk +++ b/main/sax/Library_expwrap.mk @@ -43,7 +43,7 @@ $(eval $(call gb_Library_add_linked_libs,expwrap,\ $(gb_STDLIBS) \ )) -$(call gb_Library_use_external,expwrap,expat_utf16) +$(call gb_Library_use_external,expwrap,libxml2) $(eval $(call gb_Library_add_exception_objects,expwrap,\ sax/source/expatwrap/attrlistimpl \ diff --git a/main/sax/source/expatwrap/sax_expat.cxx b/main/sax/source/expatwrap/sax_expat.cxx index 4c47cfe475..684623e038 100644 --- a/main/sax/source/expatwrap/sax_expat.cxx +++ b/main/sax/source/expatwrap/sax_expat.cxx @@ -39,7 +39,10 @@ #include <cppuhelper/implbase1.hxx> #include <cppuhelper/implbase2.hxx> -#include <expat.h> +#include <libxml/parser.h> +#ifndef LIBXML_SAX1_ENABLED +# error We need SAX1 but LIBXML_SAX1_ENABLED is undefined +#endif using namespace ::rtl; using namespace ::std; @@ -58,47 +61,9 @@ using namespace ::com::sun::star::io; namespace sax_expatwrap { -// Useful macros for correct String conversion depending on the chosen expat-mode -#ifdef XML_UNICODE -OUString XmlNChar2OUString( const XML_Char *p , int nLen ) -{ - if( p ) { - if( sizeof( sal_Unicode ) == sizeof( XML_Char ) ) - { - return OUString( (sal_Unicode*)p,nLen); - } - else - { - sal_Unicode *pWchar = (sal_Unicode *)alloca( sizeof( sal_Unicode ) * nLen ); - for( int n = 0 ; n < nLen ; n++ ) { - pWchar[n] = (sal_Unicode) p[n]; - } - return OUString( pWchar , nLen ); - } - } - else { - return OUString(); - } -} - -OUString XmlChar2OUString( const XML_Char *p ) -{ - if( p ) { - int nLen; - for( nLen = 0 ; p[nLen] ; nLen ++ ) - ; - return XmlNChar2OUString( p , nLen ); - } - else return OUString(); -} - - -#define XML_CHAR_TO_OUSTRING(x) XmlChar2OUString(x) -#define XML_CHAR_N_TO_USTRING(x,n) XmlNChar2OUString(x,n) -#else -#define XML_CHAR_TO_OUSTRING(x) OUString(x , strlen( x ), RTL_TEXTENCODING_UTF8) -#define XML_CHAR_N_TO_USTRING(x,n) OUString(x,n, RTL_TEXTENCODING_UTF8 ) -#endif +// Useful macros for correct String conversion +#define XML_CHAR_TO_OUSTRING(x) OUString((const char*)x , xmlStrlen( x ), RTL_TEXTENCODING_UTF8) +#define XML_CHAR_N_TO_USTRING(x,n) OUString((const char*)x,n, RTL_TEXTENCODING_UTF8 ) /* @@ -215,7 +180,8 @@ Sequence< OUString > SaxExpatParser::getSupportedServiceNames_Static(void) thro struct Entity { InputSource structSource; - XML_Parser pParser; + xmlSAXHandler sax; + xmlParserCtxtPtr pParser; XMLFile2UTFConverter converter; }; @@ -258,41 +224,36 @@ public: // module scope 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 ); + void static callbackStartElement(void *userData, const xmlChar *name , const xmlChar **atts); + void static callbackEndElement(void *userData, const xmlChar *name); + void static callbackCharacters( void *userData , const xmlChar *s , int nLen ); void static callbackProcessingInstruction( void *userData , - const XML_Char *sTarget , - const XML_Char *sData ); + const xmlChar *sTarget , + const xmlChar *sData ); void static callbackUnparsedEntityDecl( void *userData , - const XML_Char *entityName, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId, - const XML_Char *notationName); + const xmlChar *entityName, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName); void static callbackNotationDecl( void *userData, - const XML_Char *notationName, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId); + const xmlChar *notationName, + const xmlChar *publicId, + const xmlChar *systemId); +#if 0 int static callbackExternalEntityRef( XML_Parser parser, const XML_Char *openEntityNames, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId); - int static callbackUnknownEncoding(void *encodingHandlerData, - const XML_Char *name, - XML_Encoding *info); - void static callbackDefault( void *userData, const XML_Char *s, int len); +#endif - void static callbackStartCDATA( void *userData ); - void static callbackEndCDATA( void *userData ); - void static callbackComment( void *userData , const XML_Char *s ); + void static callbackCDATABlock( void *userData, const xmlChar *s, int len ); + void static callbackComment( void *userData , const xmlChar *s ); void static callErrorHandler( SaxExpatParser_Impl *pImpl , const SAXParseException &e ); public: @@ -301,39 +262,38 @@ public: extern "C" { - static void call_callbackStartElement(void *userData, const XML_Char *name , const XML_Char **atts) + static void call_callbackStartElement(void *userData, const xmlChar *name , const xmlChar **atts) { SaxExpatParser_Impl::callbackStartElement(userData,name,atts); } - static void call_callbackEndElement(void *userData, const XML_Char *name) + static void call_callbackEndElement(void *userData, const xmlChar *name) { SaxExpatParser_Impl::callbackEndElement(userData,name); } - static void call_callbackCharacters( void *userData , const XML_Char *s , int nLen ) + static void call_callbackCharacters( void *userData , const xmlChar *s , int nLen ) { SaxExpatParser_Impl::callbackCharacters(userData,s,nLen); } - static void call_callbackProcessingInstruction(void *userData,const XML_Char *sTarget,const XML_Char *sData ) + static void call_callbackProcessingInstruction(void *userData,const xmlChar *sTarget,const xmlChar *sData ) { SaxExpatParser_Impl::callbackProcessingInstruction(userData,sTarget,sData ); } static void call_callbackUnparsedEntityDecl(void *userData , - const XML_Char *entityName, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId, - const XML_Char *notationName) + const xmlChar *entityName, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName) { - SaxExpatParser_Impl::callbackUnparsedEntityDecl(userData,entityName,base,systemId,publicId,notationName); + SaxExpatParser_Impl::callbackUnparsedEntityDecl(userData,entityName,publicId,systemId,notationName); } static void call_callbackNotationDecl(void *userData, - const XML_Char *notationName, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId) + const xmlChar *notationName, + const xmlChar *publicId, + const xmlChar *systemId) { - SaxExpatParser_Impl::callbackNotationDecl(userData,notationName,base,systemId,publicId); + SaxExpatParser_Impl::callbackNotationDecl(userData,notationName,publicId,systemId); } +#if 0 static int call_callbackExternalEntityRef(XML_Parser parser, const XML_Char *openEntityNames, const XML_Char *base, @@ -341,26 +301,17 @@ extern "C" const XML_Char *publicId) { return SaxExpatParser_Impl::callbackExternalEntityRef(parser,openEntityNames,base,systemId,publicId); - } - static int call_callbackUnknownEncoding(void *encodingHandlerData, - const XML_Char *name, - XML_Encoding *info) - { - return SaxExpatParser_Impl::callbackUnknownEncoding(encodingHandlerData,name,info); } static void call_callbackDefault( void *userData, const XML_Char *s, int len) { SaxExpatParser_Impl::callbackDefault(userData,s,len); } - static void call_callbackStartCDATA( void *userData ) - { - SaxExpatParser_Impl::callbackStartCDATA(userData); - } - static void call_callbackEndCDATA( void *userData ) +#endif + static void call_callbackCDATABlock( void *userData, const xmlChar *s, int len ) { - SaxExpatParser_Impl::callbackEndCDATA(userData); + SaxExpatParser_Impl::callbackCDATABlock(userData, s, len); } - static void call_callbackComment( void *userData , const XML_Char *s ) + static void call_callbackComment( void *userData , const xmlChar *s ) { SaxExpatParser_Impl::callbackComment(userData,s); } @@ -383,11 +334,11 @@ public: public: //XLocator virtual sal_Int32 SAL_CALL getColumnNumber(void) throw () { - return XML_GetCurrentColumnNumber( m_pParser->getEntity().pParser ); + return xmlSAX2GetColumnNumber( m_pParser->getEntity().pParser ); } virtual sal_Int32 SAL_CALL getLineNumber(void) throw () { - return XML_GetCurrentLineNumber( m_pParser->getEntity().pParser ); + return xmlSAX2GetLineNumber( m_pParser->getEntity().pParser ); } virtual OUString SAL_CALL getPublicId(void) throw () { @@ -405,11 +356,13 @@ public: //XLocator } virtual sal_Int64 SAL_CALL getPosition() throw() { - return XML_GetCurrentByteIndex( m_pParser->getEntity().pParser ); + xmlParserCtxtPtr parser = m_pParser->getEntity().pParser; + return parser && parser->input ? parser->input->consumed : 0; } virtual ::sal_Int64 SAL_CALL getLength() throw() { - return 0; + xmlParserCtxtPtr parser = m_pParser->getEntity().pParser; + return parser && parser->input ? parser->input->length : 0; } private: @@ -473,38 +426,33 @@ void SaxExpatParser::parseStream( const InputSource& structSource) OUStringToOString( entity.structSource.sEncoding , RTL_TEXTENCODING_ASCII_US ) ); } - // create parser with proper encoding - entity.pParser = XML_ParserCreate( 0 ); - if( ! entity.pParser ) - { - throw SAXException( OUString::createFromAscii( "Couldn't create parser" ) , - Reference< XInterface > (), Any() ); - } - // set all necessary C-Callbacks - XML_SetUserData( entity.pParser , m_pImpl ); - XML_SetElementHandler( entity.pParser , - call_callbackStartElement , - call_callbackEndElement ); - XML_SetCharacterDataHandler( entity.pParser , call_callbackCharacters ); - XML_SetProcessingInstructionHandler(entity.pParser , - call_callbackProcessingInstruction ); - XML_SetUnparsedEntityDeclHandler( entity.pParser, - call_callbackUnparsedEntityDecl ); - XML_SetNotationDeclHandler( entity.pParser, call_callbackNotationDecl ); - XML_SetExternalEntityRefHandler( entity.pParser, - call_callbackExternalEntityRef); - XML_SetUnknownEncodingHandler( entity.pParser, call_callbackUnknownEncoding ,0); + memset( &entity.sax, 0, sizeof(entity.sax) ); + entity.sax.initialized = XML_SAX2_MAGIC; + entity.sax.startElement = call_callbackStartElement; + entity.sax.endElement = call_callbackEndElement; + entity.sax.characters = call_callbackCharacters; + entity.sax.processingInstruction = call_callbackProcessingInstruction; + entity.sax.unparsedEntityDecl = call_callbackUnparsedEntityDecl; + entity.sax.notationDecl = call_callbackNotationDecl; +// XML_SetExternalEntityRefHandler( entity.pParser, +// call_callbackExternalEntityRef); if( m_pImpl->rExtendedDocumentHandler.is() ) { // These handlers just delegate calls to the ExtendedHandler. If no extended handler is // given, these callbacks can be ignored - XML_SetDefaultHandlerExpand( entity.pParser, call_callbackDefault ); - XML_SetCommentHandler( entity.pParser, call_callbackComment ); - XML_SetCdataSectionHandler( entity.pParser , - call_callbackStartCDATA , - call_callbackEndCDATA ); +// XML_SetDefaultHandlerExpand( entity.pParser, call_callbackDefault ); + entity.sax.comment = call_callbackComment; + entity.sax.cdataBlock = call_callbackCDATABlock; + } + + // create parser with proper encoding + entity.pParser = xmlCreatePushParserCtxt( &entity.sax, m_pImpl, NULL, 0, NULL ); + if( ! entity.pParser ) + { + throw SAXException( OUString::createFromAscii( "Couldn't create parser" ) , + Reference< XInterface > (), Any() ); } @@ -528,7 +476,7 @@ void SaxExpatParser::parseStream( const InputSource& structSource) // catch( SAXParseException &e ) // { // m_pImpl->popEntity(); -// XML_ParserFree( entity.pParser ); +// xmlFreeParserCtxt( entity.pParser ); // Any aAny; // aAny <<= e; // throw SAXException( e.Message, e.Context, aAny ); @@ -536,24 +484,24 @@ void SaxExpatParser::parseStream( const InputSource& structSource) catch( SAXException & ) { m_pImpl->popEntity(); - XML_ParserFree( entity.pParser ); + xmlFreeParserCtxt( entity.pParser ); throw; } catch( IOException & ) { m_pImpl->popEntity(); - XML_ParserFree( entity.pParser ); + xmlFreeParserCtxt( entity.pParser ); throw; } catch( RuntimeException & ) { m_pImpl->popEntity(); - XML_ParserFree( entity.pParser ); + xmlFreeParserCtxt( entity.pParser ); throw; } m_pImpl->popEntity(); - XML_ParserFree( entity.pParser ); + xmlFreeParserCtxt( entity.pParser ); } void SaxExpatParser::setDocumentHandler(const Reference< XDocumentHandler > & xHandler) @@ -623,86 +571,16 @@ Sequence< OUString > SaxExpatParser::getSupportedServiceNames(void) throw () * * *-------------------------------------------*/ -OUString getErrorMessage( XML_Error xmlE, OUString sSystemId , sal_Int32 nLine ) +OUString getErrorMessage( int xmlE, OUString &errorMessage, 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" ); + str += OUString::createFromAscii( "][code " ); + str += OUString::valueOf( xmlE ); + str += OUString::createFromAscii( "]: " ); + str += errorMessage; return str; } @@ -720,30 +598,32 @@ void SaxExpatParser_Impl::parse( ) nRead = getEntity().converter.readAndConvert( seqOut , nBufSize ); if( ! nRead ) { - XML_Parse( getEntity().pParser , - ( const char * ) seqOut.getArray() , - 0 , - 1 ); + xmlParseChunk( getEntity().pParser , + ( const char * ) seqOut.getArray() , + 0 , + 1 ); break; } - sal_Bool bContinue = ( XML_Parse( getEntity().pParser , - (const char *) seqOut.getArray(), - nRead, - 0 ) != 0 ); + int xmlE = xmlParseChunk( getEntity().pParser , + (const char *) seqOut.getArray(), + nRead, + 0 ); - if( ! bContinue || this->bExceptionWasThrown ) { + if( xmlE != XML_ERR_OK || this->bExceptionWasThrown ) { if ( this->bRTExceptionWasThrown ) throw rtexception; + xmlErrorPtr xmlEPtr = xmlCtxtGetLastError( getEntity().pParser ); + OUString errorString = OUString::createFromAscii( xmlEPtr != NULL && xmlEPtr->message != NULL ? xmlEPtr->message : "" ); + // Error during parsing ! - XML_Error xmlE = XML_GetErrorCode( getEntity().pParser ); OUString sSystemId = rDocumentLocator->getSystemId(); sal_Int32 nLine = rDocumentLocator->getLineNumber(); SAXParseException aExcept( - getErrorMessage(xmlE , sSystemId, nLine) , + getErrorMessage(xmlE , errorString, sSystemId, nLine) , Reference< XInterface >(), Any( &exception , getCppuType( &exception) ), rDocumentLocator->getPublicId(), @@ -773,8 +653,8 @@ void SaxExpatParser_Impl::parse( ) // //----------------------------------------- void SaxExpatParser_Impl::callbackStartElement( void *pvThis , - const XML_Char *pwName , - const XML_Char **awAttributes ) + const xmlChar *pwName , + const xmlChar **awAttributes ) { // in case of two concurrent threads, there is only the danger of an leak, // which is neglectable for one string @@ -787,13 +667,15 @@ void SaxExpatParser_Impl::callbackStartElement( void *pvThis , int i = 0; pImpl->pAttrList->clear(); - while( awAttributes[i] ) { - OSL_ASSERT( awAttributes[i+1] ); - pImpl->pAttrList->addAttribute( - XML_CHAR_TO_OUSTRING( awAttributes[i] ) , - g_CDATA , // expat doesn't know types - XML_CHAR_TO_OUSTRING( awAttributes[i+1] ) ); - i +=2; + if ( awAttributes ) { + while( awAttributes[i] ) { + OSL_ASSERT( awAttributes[i+1] ); + pImpl->pAttrList->addAttribute( + XML_CHAR_TO_OUSTRING( awAttributes[i] ) , + g_CDATA , // expat doesn't know types + XML_CHAR_TO_OUSTRING( awAttributes[i+1] ) ); + i +=2; + } } CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( @@ -803,7 +685,7 @@ void SaxExpatParser_Impl::callbackStartElement( void *pvThis , } } -void SaxExpatParser_Impl::callbackEndElement( void *pvThis , const XML_Char *pwName ) +void SaxExpatParser_Impl::callbackEndElement( void *pvThis , const xmlChar *pwName ) { SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis); @@ -814,7 +696,7 @@ void SaxExpatParser_Impl::callbackEndElement( void *pvThis , const XML_Char *pwN } -void SaxExpatParser_Impl::callbackCharacters( void *pvThis , const XML_Char *s , int nLen ) +void SaxExpatParser_Impl::callbackCharacters( void *pvThis , const xmlChar *s , int nLen ) { SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis); @@ -825,8 +707,8 @@ void SaxExpatParser_Impl::callbackCharacters( void *pvThis , const XML_Char *s , } void SaxExpatParser_Impl::callbackProcessingInstruction( void *pvThis, - const XML_Char *sTarget , - const XML_Char *sData ) + const xmlChar *sTarget , + const xmlChar *sData ) { SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis); if( pImpl->rDocumentHandler.is() ) { @@ -839,11 +721,10 @@ void SaxExpatParser_Impl::callbackProcessingInstruction( void *pvThis, void SaxExpatParser_Impl::callbackUnparsedEntityDecl(void *pvThis , - const XML_Char *entityName, - const XML_Char * /*base*/, - const XML_Char *systemId, - const XML_Char *publicId, - const XML_Char *notationName) + const xmlChar *entityName, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName) { SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis); if( pImpl->rDTDHandler.is() ) { @@ -858,10 +739,9 @@ void SaxExpatParser_Impl::callbackUnparsedEntityDecl(void *pvThis , } void SaxExpatParser_Impl::callbackNotationDecl( void *pvThis, - const XML_Char *notationName, - const XML_Char * /*base*/, - const XML_Char *systemId, - const XML_Char *publicId) + const xmlChar *notationName, + const xmlChar *publicId, + const xmlChar *systemId) { SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis); if( pImpl->rDTDHandler.is() ) { @@ -874,7 +754,7 @@ void SaxExpatParser_Impl::callbackNotationDecl( void *pvThis, } - +#if 0 int SaxExpatParser_Impl::callbackExternalEntityRef( XML_Parser parser, const XML_Char *context, const XML_Char * /*base*/, @@ -948,13 +828,6 @@ int SaxExpatParser_Impl::callbackExternalEntityRef( XML_Parser parser, return bOK; } -int SaxExpatParser_Impl::callbackUnknownEncoding(void * /*encodingHandlerData*/, - const XML_Char * /*name*/, - XML_Encoding * /*info*/) -{ - return 0; -} - void SaxExpatParser_Impl::callbackDefault( void *pvThis, const XML_Char *s, int len) { SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis); @@ -962,19 +835,21 @@ void SaxExpatParser_Impl::callbackDefault( void *pvThis, const XML_Char *s, in CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl, rExtendedDocumentHandler->unknown( XML_CHAR_N_TO_USTRING( s ,len) ) ); } - -void SaxExpatParser_Impl::callbackComment( void *pvThis , const XML_Char *s ) +#endif +void SaxExpatParser_Impl::callbackComment( void *pvThis , const xmlChar *s ) { SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis); CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl, rExtendedDocumentHandler->comment( XML_CHAR_TO_OUSTRING( s ) ) ); } -void SaxExpatParser_Impl::callbackStartCDATA( void *pvThis ) +void SaxExpatParser_Impl::callbackCDATABlock( void *pvThis, const xmlChar *s, int len ) { SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis); CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl, rExtendedDocumentHandler->startCDATA() ); + callbackCharacters( pvThis, s, len ); + CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(pImpl,rExtendedDocumentHandler->endCDATA() ); } @@ -1011,13 +886,6 @@ void SaxExpatParser_Impl::callErrorHandler( SaxExpatParser_Impl *pImpl , } } -void SaxExpatParser_Impl::callbackEndCDATA( void *pvThis ) -{ - SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis); - - CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(pImpl,rExtendedDocumentHandler->endCDATA() ); -} - } using namespace sax_expatwrap;
--------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@openoffice.apache.org For additional commands, e-mail: dev-h...@openoffice.apache.org