/**************************************************************
 * 
 * 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
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/


#include <stdlib.h>
#include <string.h>
#include <sal/alloca.h>
#include <vector>

#include <osl/diagnose.h>

#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/util/XCloneable.hpp>
#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
#include <com/sun/star/xml/sax/XParser.hpp>
#include <com/sun/star/xml/sax/SAXParseException.hpp>
#include <com/sun/star/io/XSeekable.hpp>

#include <cppuhelper/factory.hxx>
#include <cppuhelper/weak.hxx>
#include <cppuhelper/implbase1.hxx>
#include <cppuhelper/implbase2.hxx>

#include <expat.h>

using namespace ::rtl;
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;

#include "factory.hxx"
#include "attrlistimpl.hxx"
#include "xml2utf.hxx"

namespace sax_expatwrap {
	
// Useful macros for correct String conversion depending on the choosen 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


/*
* The following macro encapsulates any call to an event handler. 
* It ensures, that exceptions thrown by the event handler are
* treated properly. 
*/
#define CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(pThis,call) \
	if( ! pThis->bExceptionWasThrown ) { \
		try {\
			pThis->call;\
		}\
		catch( SAXParseException &e ) {\
			pThis->callErrorHandler( pThis ,  e );\
	 	}\
		catch( SAXException &e ) {\
			pThis->callErrorHandler( pThis , SAXParseException(\
											e.Message, \
											e.Context, \
											e.WrappedException,\
											pThis->rDocumentLocator->getPublicId(),\
											pThis->rDocumentLocator->getSystemId(),\
											pThis->rDocumentLocator->getLineNumber(),\
											pThis->rDocumentLocator->getColumnNumber()\
									 ) );\
        }\
        catch( com::sun::star::uno::RuntimeException &e ) {\
            pThis->bExceptionWasThrown = sal_True; \
            pThis->bRTExceptionWasThrown = sal_True; \
			pImpl->rtexception = e; \
		}\
	}\
	((void)0)

#define IMPLEMENTATION_NAME	"com.sun.star.comp.extensions.xml.sax.ParserExpat"
#define SERVICE_NAME		"com.sun.star.xml.sax.Parser"

class SaxExpatParser_Impl;


// This class implements the external Parser interface
class SaxExpatParser :
	public WeakImplHelper2<
				XParser,
				XServiceInfo
                          >
{
	
public:	
	SaxExpatParser();
	~SaxExpatParser();
	
public:

	// The implementation details
    static Sequence< OUString > 	getSupportedServiceNames_Static(void) throw ();

public:
	// The SAX-Parser-Interface
    virtual void SAL_CALL parseStream(	const InputSource& structSource)
		throw (	SAXException, 
				IOException, 
				RuntimeException);
    virtual void SAL_CALL setDocumentHandler(const Reference< XDocumentHandler > & xHandler) 
		throw (RuntimeException);
	
    virtual void SAL_CALL setErrorHandler(const Reference< XErrorHandler > & xHandler)
		throw (RuntimeException);
    virtual void SAL_CALL setDTDHandler(const Reference < XDTDHandler > & xHandler)
		throw (RuntimeException);
    virtual void SAL_CALL setEntityResolver(const Reference<  XEntityResolver >& xResolver)
		throw (RuntimeException);

	virtual void SAL_CALL setLocale( const Locale &locale ) 					throw (RuntimeException);
	
public: // XServiceInfo
    OUString                     SAL_CALL getImplementationName() throw ();
    Sequence< OUString >         SAL_CALL getSupportedServiceNames(void) throw ();
    sal_Bool                     SAL_CALL supportsService(const OUString& ServiceName) throw ();

private:

	SaxExpatParser_Impl 		*m_pImpl;
	
};

//--------------------------------------
// the extern interface 
//---------------------------------------
Reference< XInterface > SAL_CALL SaxExpatParser_CreateInstance(
	const Reference< XMultiServiceFactory  >  & ) throw(Exception)
{	
	SaxExpatParser *p = new SaxExpatParser;

	return Reference< XInterface > ( (OWeakObject * ) p );
}



Sequence< OUString > 	SaxExpatParser::getSupportedServiceNames_Static(void) throw ()
{
	Sequence<OUString> aRet(1);
	aRet.getArray()[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(SERVICE_NAME) );
	return aRet;
}


//---------------------------------------------
// the implementation part
//---------------------------------------------


// Entity binds all information neede for a single file
struct Entity
{
	InputSource			structSource;
	XML_Parser			pParser;	
	XMLFile2UTFConverter converter;
};


class SaxExpatParser_Impl
{
public: // module scope
	Mutex				aMutex;

	Reference< XDocumentHandler >	rDocumentHandler;
	Reference< XExtendedDocumentHandler > rExtendedDocumentHandler;
	
	Reference< XErrorHandler > 	rErrorHandler;
	Reference< XDTDHandler > 	rDTDHandler;
	Reference< XEntityResolver > rEntityResolver;
	Reference < XLocator >		rDocumentLocator;


	Reference < XAttributeList >	rAttrList;
	AttributeList	*pAttrList;

	// External entity stack 
	vector<struct Entity> 	vecEntity;
	void pushEntity( const struct Entity &entity )
		{ vecEntity.push_back( entity ); }
	void popEntity()
		{ vecEntity.pop_back( ); }
	struct Entity &getEntity()
		{ return vecEntity.back(); }


	// Exception cannot be thrown through the C-XmlParser (possible resource leaks), 
	// therefor the exception must be saved somewhere.
	SAXParseException 	exception;
    RuntimeException    rtexception;
	sal_Bool 			bExceptionWasThrown;
    sal_Bool            bRTExceptionWasThrown;

	Locale				locale;

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 callbackProcessingInstruction( 	void *userData , 
												const XML_Char *sTarget , 
												const XML_Char *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);
					      					
	void static callbackNotationDecl(	void *userData,
										const XML_Char *notationName,
										const XML_Char *base,
										const XML_Char *systemId,
										const XML_Char *publicId);

	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);

	void static callbackStartCDATA( void *userData );
	void static callbackEndCDATA( void *userData );
	void static callbackComment( void *userData , const XML_Char *s );
	void static callErrorHandler( SaxExpatParser_Impl *pImpl , const SAXParseException &e );

public:
	void parse();
};

extern "C"
{
    static void call_callbackStartElement(void *userData, const XML_Char *name , const XML_Char **atts)
    {
        SaxExpatParser_Impl::callbackStartElement(userData,name,atts);
    }
	static void call_callbackEndElement(void *userData, const XML_Char *name)
    {
        SaxExpatParser_Impl::callbackEndElement(userData,name);
    }
	static void call_callbackCharacters( void *userData , const XML_Char *s , int nLen )
    {
        SaxExpatParser_Impl::callbackCharacters(userData,s,nLen);
    }
	static void call_callbackProcessingInstruction(void *userData,const XML_Char *sTarget,const XML_Char *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)
    {
        SaxExpatParser_Impl::callbackUnparsedEntityDecl(userData,entityName,base,systemId,publicId,notationName);
    }
	static void call_callbackNotationDecl(void *userData,
                                          const XML_Char *notationName,
                                          const XML_Char *base,
                                          const XML_Char *systemId,
                                          const XML_Char *publicId)
    {
        SaxExpatParser_Impl::callbackNotationDecl(userData,notationName,base,systemId,publicId);
    }
	static int call_callbackExternalEntityRef(XML_Parser parser,
					    					  const XML_Char *openEntityNames,
                                              const XML_Char *base,
                                              const XML_Char *systemId,
                                              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 )
    {
        SaxExpatParser_Impl::callbackEndCDATA(userData);
    }
	static void call_callbackComment( void *userData , const XML_Char *s )
    {
        SaxExpatParser_Impl::callbackComment(userData,s);
    }
}


//---------------------------------------------
// LocatorImpl
//---------------------------------------------
class LocatorImpl :
    public WeakImplHelper2< XLocator, com::sun::star::io::XSeekable >
    // should use a different interface for stream positions!
{
public:
	LocatorImpl( SaxExpatParser_Impl *p )
	{
		m_pParser 	 = p;
	}
	
public: //XLocator
    virtual sal_Int32 SAL_CALL getColumnNumber(void) throw ()
    {
    	return XML_GetCurrentColumnNumber( m_pParser->getEntity().pParser );
    }
    virtual sal_Int32 SAL_CALL getLineNumber(void) throw ()
    {
    	return XML_GetCurrentLineNumber( m_pParser->getEntity().pParser );
    }
    virtual OUString SAL_CALL getPublicId(void) throw ()
    {
    	return m_pParser->getEntity().structSource.sPublicId;
    }
    virtual OUString SAL_CALL getSystemId(void) throw ()
    {
    	return m_pParser->getEntity().structSource.sSystemId;
    }

    // XSeekable (only for getPosition)

    virtual void SAL_CALL seek( sal_Int64 ) throw()
    {
    }
    virtual sal_Int64 SAL_CALL getPosition() throw()
    {
        return XML_GetCurrentByteIndex( m_pParser->getEntity().pParser );
    }
    virtual ::sal_Int64 SAL_CALL getLength() throw()
    {
        return 0;
    }

private:

	SaxExpatParser_Impl *m_pParser;
};		




SaxExpatParser::SaxExpatParser(  )
{
	m_pImpl = new SaxExpatParser_Impl;

	LocatorImpl *pLoc = new LocatorImpl( m_pImpl );
	m_pImpl->rDocumentLocator = Reference< XLocator > ( pLoc );
	 
	// performance-Improvment. Reference is needed when calling the startTag callback.
	// Handing out the same object with every call is allowed (see sax-specification)
	m_pImpl->pAttrList = new AttributeList;
	m_pImpl->rAttrList = Reference< XAttributeList > ( m_pImpl->pAttrList );
	
	m_pImpl->bExceptionWasThrown = sal_False;
	m_pImpl->bRTExceptionWasThrown = sal_False;
}

SaxExpatParser::~SaxExpatParser()
{
	delete m_pImpl;	
}


/***************
*
* parseStream does Parser-startup initializations. The SaxExpatParser_Impl::parse() method does
* the file-specific initialization work. (During a parser run, external files may be opened)
* 
****************/
void SaxExpatParser::parseStream(	const InputSource& structSource)
	throw (SAXException, 
		   IOException, 
		   RuntimeException)
{
	// Only one text at one time
	MutexGuard guard( m_pImpl->aMutex );
	
	
	struct Entity entity;
	entity.structSource = structSource;

	if( ! entity.structSource.aInputStream.is() )
	{
		throw SAXException( OUString::createFromAscii( "No input source" ) ,
							Reference< XInterface > () , Any() );
	}

	entity.converter.setInputStream( entity.structSource.aInputStream );
	if( entity.structSource.sEncoding.getLength() )
	{
		entity.converter.setEncoding(
			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);
	
	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 );
	}


	m_pImpl->exception = SAXParseException();
	m_pImpl->pushEntity( entity );
	try
	{
		// start the document
		if( m_pImpl->rDocumentHandler.is() ) {
			m_pImpl->rDocumentHandler->setDocumentLocator( m_pImpl->rDocumentLocator );
			m_pImpl->rDocumentHandler->startDocument();
		}

		m_pImpl->parse();

		// finish document
		if( m_pImpl->rDocumentHandler.is() ) {
			m_pImpl->rDocumentHandler->endDocument();	
		}
	}
//  	catch( SAXParseException &e ) 
// 	{
// 		m_pImpl->popEntity();
//  		XML_ParserFree( entity.pParser );
//        Any aAny;
//        aAny <<= e;
//  		throw SAXException( e.Message, e.Context, aAny );
//  	}
	catch( SAXException & )
	{
		m_pImpl->popEntity();
		XML_ParserFree( entity.pParser );
  		throw;
	}
	catch( IOException & )
	{
		m_pImpl->popEntity();
		XML_ParserFree( entity.pParser );
		throw;
	}
	catch( RuntimeException & )
	{
		m_pImpl->popEntity();
		XML_ParserFree( entity.pParser );
		throw;
	}

	m_pImpl->popEntity();
	XML_ParserFree( entity.pParser );
}
    																			
void SaxExpatParser::setDocumentHandler(const Reference< XDocumentHandler > & xHandler) 
	throw (RuntimeException)
{
	m_pImpl->rDocumentHandler = xHandler;
	m_pImpl->rExtendedDocumentHandler =
		Reference< XExtendedDocumentHandler >( xHandler , UNO_QUERY );
}
    																
void SaxExpatParser::setErrorHandler(const Reference< XErrorHandler > & xHandler)
	throw (RuntimeException)
{
	m_pImpl->rErrorHandler = xHandler;
}

void SaxExpatParser::setDTDHandler(const Reference< XDTDHandler > & xHandler)
	throw (RuntimeException)
{
	m_pImpl->rDTDHandler = xHandler;
}

void SaxExpatParser::setEntityResolver(const Reference < XEntityResolver > & xResolver)
	throw (RuntimeException)
{
	m_pImpl->rEntityResolver = xResolver;
}


void SaxExpatParser::setLocale( const Locale & locale )	throw (RuntimeException)
{
	m_pImpl->locale = locale;	
}

// XServiceInfo
OUString SaxExpatParser::getImplementationName() throw ()
{
    return OUString::createFromAscii( IMPLEMENTATION_NAME );
}

// XServiceInfo
sal_Bool SaxExpatParser::supportsService(const OUString& ServiceName) throw ()
{
    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 > SaxExpatParser::getSupportedServiceNames(void) throw ()
{
    
    Sequence<OUString> 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 SaxExpatParser_Impl::parse( )
{
	const int nBufSize = 16*1024;

	int nRead   = nBufSize;
	Sequence< sal_Int8 > seqOut(nBufSize);

	while( nRead ) {
		nRead = getEntity().converter.readAndConvert( seqOut , nBufSize );

		if( ! nRead ) {				
			XML_Parse( getEntity().pParser , 
                                   ( const char * ) seqOut.getArray() , 
                                   0 , 
                                   1 );	
			break;
		}		

		sal_Bool bContinue = ( XML_Parse( getEntity().pParser ,
                                                (const char *) seqOut.getArray(),
                                                nRead,
                                                0 ) != 0 );
		
		if( ! bContinue || this->bExceptionWasThrown ) {
			
            if ( this->bRTExceptionWasThrown )
                throw rtexception;

			// 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) , 
				Reference< XInterface >(), 
				Any( &exception , getCppuType( &exception) ),
				rDocumentLocator->getPublicId(),
				rDocumentLocator->getSystemId(),
				rDocumentLocator->getLineNumber(),
				rDocumentLocator->getColumnNumber()
				);
			
			if( rErrorHandler.is() ) {

				// error handler is set, so the handler may throw the exception
				Any a;
				a <<= aExcept;
				rErrorHandler->fatalError( a );
			}

			// Error handler has not thrown an exception, but parsing cannot go on,
			// so an exception MUST be thrown.
			throw aExcept;
		} // if( ! bContinue )
	} // while
}

//------------------------------------------
//
// The C-Callbacks
//
//-----------------------------------------
void SaxExpatParser_Impl::callbackStartElement( void *pvThis , 
												const XML_Char *pwName , 
												const XML_Char **awAttributes )
{
    // in case of two concurrent threads, there is only the danger of an leak,
    // which is neglectable for one string
    static OUString g_CDATA( RTL_CONSTASCII_USTRINGPARAM( "CDATA" ) );
    
	SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis);
	
	if( pImpl->rDocumentHandler.is() ) {

		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;	
		}

		CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(
			pImpl , 
			rDocumentHandler->startElement( XML_CHAR_TO_OUSTRING( pwName ) , 
											pImpl->rAttrList ) );
	}
}

void SaxExpatParser_Impl::callbackEndElement( void *pvThis , const XML_Char *pwName  )
{
	SaxExpatParser_Impl  *pImpl = ((SaxExpatParser_Impl*)pvThis);
	
	if( pImpl->rDocumentHandler.is() ) {
		CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl,
				rDocumentHandler->endElement( XML_CHAR_TO_OUSTRING( pwName ) ) );
	}
}


void SaxExpatParser_Impl::callbackCharacters( void *pvThis , const XML_Char *s , int nLen )
{
	SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis);

	if( pImpl->rDocumentHandler.is() ) {
		CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl , 
				rDocumentHandler->characters( XML_CHAR_N_TO_USTRING(s,nLen) ) );
	}
}

void SaxExpatParser_Impl::callbackProcessingInstruction(	void *pvThis,
													const XML_Char *sTarget , 
													const XML_Char *sData )
{
	SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis);
	if( pImpl->rDocumentHandler.is() ) {
		CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( 
                    pImpl ,
                    rDocumentHandler->processingInstruction( XML_CHAR_TO_OUSTRING( sTarget ),
                    XML_CHAR_TO_OUSTRING( sData ) ) );
	}	
}


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)
{
	SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis);
	if( pImpl->rDTDHandler.is() ) {
		CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(
			pImpl , 
			rDTDHandler->unparsedEntityDecl(
				XML_CHAR_TO_OUSTRING( entityName ), 
				XML_CHAR_TO_OUSTRING( publicId ) ,
				XML_CHAR_TO_OUSTRING( systemId ) ,
				XML_CHAR_TO_OUSTRING( notationName ) ) );
	}
}
					      					
void SaxExpatParser_Impl::callbackNotationDecl(	void *pvThis,
                                                const XML_Char *notationName,
                                                const XML_Char * /*base*/,
                                                const XML_Char *systemId,
                                                const XML_Char *publicId)
{
	SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis);
	if( pImpl->rDTDHandler.is() ) {		
		CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl,
			    rDTDHandler->notationDecl( 	XML_CHAR_TO_OUSTRING( notationName ) ,
											XML_CHAR_TO_OUSTRING( publicId ) ,
											XML_CHAR_TO_OUSTRING( systemId ) ) );
	}

}										



int SaxExpatParser_Impl::callbackExternalEntityRef( XML_Parser parser,
                                                    const XML_Char *context,
                                                    const XML_Char * /*base*/,
                                                    const XML_Char *systemId,
                                                    const XML_Char *publicId)
{
	sal_Bool bOK = sal_True;
	InputSource source;
	SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)XML_GetUserData( parser ));

	struct Entity entity;
	
	if( pImpl->rEntityResolver.is() ) {
		try
		{
	    	entity.structSource = pImpl->rEntityResolver->resolveEntity(
				XML_CHAR_TO_OUSTRING( publicId ) ,
				XML_CHAR_TO_OUSTRING( systemId ) );
	    }
	    catch( SAXParseException & e )
		{
	    	pImpl->exception = e;
	    	bOK = sal_False;
	    }
	    catch( SAXException & e )
		{
	    	pImpl->exception = SAXParseException(
				e.Message , e.Context , e.WrappedException ,
				pImpl->rDocumentLocator->getPublicId(),
				pImpl->rDocumentLocator->getSystemId(),
				pImpl->rDocumentLocator->getLineNumber(),
				pImpl->rDocumentLocator->getColumnNumber() );
			bOK = sal_False;
	    }
	}

	if( entity.structSource.aInputStream.is() ) {
		entity.pParser = XML_ExternalEntityParserCreate( parser , context, 0 );
		if( ! entity.pParser )
		{
			return sal_False;
		}

		entity.converter.setInputStream( entity.structSource.aInputStream );
		pImpl->pushEntity( entity );
		try
		{
			pImpl->parse();
		}
		catch( SAXParseException & e )
		{
			pImpl->exception = e;
			bOK = sal_False;
		}
		catch( IOException &e )
		{
			pImpl->exception.WrappedException <<= e;
			bOK = sal_False;
		}
		catch( RuntimeException &e )
		{
			pImpl->exception.WrappedException <<=e;
			bOK = sal_False;
		}

		pImpl->popEntity();
		
		XML_ParserFree( entity.pParser );
	}

	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);

	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 )
{
	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 )
{
	SaxExpatParser_Impl *pImpl = ((SaxExpatParser_Impl*)pvThis);

	CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl, rExtendedDocumentHandler->startCDATA() );
}


void SaxExpatParser_Impl::callErrorHandler( SaxExpatParser_Impl *pImpl ,
											const SAXParseException & e )
{
	try
	{
		if( pImpl->rErrorHandler.is() ) {
			Any a;
			a <<= e;
			pImpl->rErrorHandler->error( a );
		}
		else {
			pImpl->exception = e;
			pImpl->bExceptionWasThrown = sal_True;
		}
	}
	catch( SAXParseException & ex ) {
		pImpl->exception = ex;
		pImpl->bExceptionWasThrown = sal_True;
	}
	catch( SAXException & ex ) {
		pImpl->exception = SAXParseException( 
									ex.Message, 
									ex.Context, 
									ex.WrappedException,
									pImpl->rDocumentLocator->getPublicId(),
									pImpl->rDocumentLocator->getSystemId(),
									pImpl->rDocumentLocator->getLineNumber(),
									pImpl->rDocumentLocator->getColumnNumber()
							 );
		pImpl->bExceptionWasThrown = sal_True;
	}		
}

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;

extern "C" 
{

void SAL_CALL component_getImplementationEnvironment(
	const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ )
{
	*ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

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,
										SaxExpatParser_CreateInstance,
										SaxExpatParser::getSupportedServiceNames_Static() );
		}
		else if ( aImplementationName == SaxWriter_getImplementationName() )
		{
			xRet = createSingleFactory( xSMgr, aImplementationName,
										SaxWriter_CreateInstance,
										SaxWriter_getSupportedServiceNames() );
		}

		if (xRet.is())
		{
			xRet->acquire();
			pRet = xRet.get();
		}
	}
	
	return pRet;
}
		

}

