/************************************************************** * * 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 #include #include #include // for the multiservice-factories #include #include #include #include #include #include #include #include #include using namespace ::std; using namespace ::rtl; using namespace ::cppu; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::test; using namespace ::com::sun::star::registry; using namespace ::com::sun::star::io; using namespace ::com::sun::star::xml::sax; #include "factory.hxx" namespace sax_test { class OFileWriter : public WeakImplHelper1< XOutputStream > { public: OFileWriter( char *pcFile ) { strncpy( m_pcFile, pcFile, 256 - 1 ); m_f = 0; } public: virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData) throw (NotConnectedException, BufferSizeExceededException, RuntimeException); virtual void SAL_CALL flush(void) throw (NotConnectedException, BufferSizeExceededException, RuntimeException); virtual void SAL_CALL closeOutput(void) throw (NotConnectedException, BufferSizeExceededException, RuntimeException); private: char m_pcFile[256]; FILE *m_f; }; void OFileWriter::writeBytes(const Sequence< sal_Int8 >& aData) throw (NotConnectedException, BufferSizeExceededException, RuntimeException) { if( ! m_f ) { m_f = fopen( m_pcFile , "w" ); } fwrite( aData.getConstArray() , 1 , aData.getLength() , m_f ); } void OFileWriter::flush(void) throw (NotConnectedException, BufferSizeExceededException, RuntimeException) { fflush( m_f ); } void OFileWriter::closeOutput(void) throw (NotConnectedException, BufferSizeExceededException, RuntimeException) { fclose( m_f ); m_f = 0; } class OSaxWriterTest : public WeakImplHelper1< XSimpleTest > { public: OSaxWriterTest( const Reference < XMultiServiceFactory > & rFactory ) : m_rFactory( rFactory ) { } ~OSaxWriterTest() {} public: virtual void SAL_CALL testInvariant( const OUString& TestName, const Reference < XInterface >& TestObject) throw ( IllegalArgumentException, RuntimeException); virtual sal_Int32 SAL_CALL test( const OUString& TestName, const Reference < XInterface >& TestObject, sal_Int32 hTestHandle) throw ( IllegalArgumentException,RuntimeException); virtual sal_Bool SAL_CALL testPassed(void) throw ( RuntimeException); virtual Sequence< OUString > SAL_CALL getErrors(void) throw (RuntimeException); virtual Sequence< Any > SAL_CALL getErrorExceptions(void) throw (RuntimeException); virtual Sequence< OUString > SAL_CALL getWarnings(void) throw (RuntimeException); private: void testSimple( const Reference< XExtendedDocumentHandler > &r ); void testExceptions( const Reference< XExtendedDocumentHandler > &r ); void testDTD( const Reference< XExtendedDocumentHandler > &r ); void testPerformance( const Reference< XExtendedDocumentHandler > &r ); void writeParagraph( const Reference< XExtendedDocumentHandler > &r , const OUString & s); private: Sequence m_seqExceptions; Sequence m_seqErrors; Sequence m_seqWarnings; Reference < XMultiServiceFactory > m_rFactory; }; /*---------------------------------------- * * Attributlist implementation * *----------------------------------------*/ struct AttributeListImpl_impl; class AttributeListImpl : public WeakImplHelper1< XAttributeList > { public: AttributeListImpl(); AttributeListImpl( const AttributeListImpl & ); ~AttributeListImpl(); public: virtual sal_Int16 SAL_CALL getLength(void) throw (RuntimeException); virtual OUString SAL_CALL getNameByIndex(sal_Int16 i) throw (RuntimeException); virtual OUString SAL_CALL getTypeByIndex(sal_Int16 i) throw (RuntimeException); virtual OUString SAL_CALL getTypeByName(const OUString& aName) throw (RuntimeException); virtual OUString SAL_CALL getValueByIndex(sal_Int16 i) throw (RuntimeException); virtual OUString SAL_CALL getValueByName(const OUString& aName) throw (RuntimeException); public: void addAttribute( const OUString &sName , const OUString &sType , const OUString &sValue ); void clear(); private: struct AttributeListImpl_impl *m_pImpl; }; struct TagAttribute { TagAttribute(){} TagAttribute( const OUString &sName, const OUString &sType , const OUString &sValue ) { this->sName = sName; this->sType = sType; this->sValue = sValue; } OUString sName; OUString sType; OUString sValue; }; struct AttributeListImpl_impl { AttributeListImpl_impl() { // performance improvement during adding vecAttribute.reserve(20); } vector vecAttribute; }; sal_Int16 AttributeListImpl::getLength(void) throw (RuntimeException) { return m_pImpl->vecAttribute.size(); } AttributeListImpl::AttributeListImpl( const AttributeListImpl &r ) { m_pImpl = new AttributeListImpl_impl; *m_pImpl = *(r.m_pImpl); } OUString AttributeListImpl::getNameByIndex(sal_Int16 i) throw (RuntimeException) { if( i < m_pImpl->vecAttribute.size() ) { return m_pImpl->vecAttribute[i].sName; } return OUString(); } OUString AttributeListImpl::getTypeByIndex(sal_Int16 i) throw (RuntimeException) { if( i < m_pImpl->vecAttribute.size() ) { return m_pImpl->vecAttribute[i].sType; } return OUString(); } OUString AttributeListImpl::getValueByIndex(sal_Int16 i) throw (RuntimeException) { if( i < m_pImpl->vecAttribute.size() ) { return m_pImpl->vecAttribute[i].sValue; } return OUString(); } OUString AttributeListImpl::getTypeByName( const OUString& sName ) throw (RuntimeException) { vector::iterator ii = m_pImpl->vecAttribute.begin(); for( ; ii != m_pImpl->vecAttribute.end() ; ii ++ ) { if( (*ii).sName == sName ) { return (*ii).sType; } } return OUString(); } OUString AttributeListImpl::getValueByName(const OUString& sName) throw (RuntimeException) { vector::iterator ii = m_pImpl->vecAttribute.begin(); for( ; ii != m_pImpl->vecAttribute.end() ; ii ++ ) { if( (*ii).sName == sName ) { return (*ii).sValue; } } return OUString(); } AttributeListImpl::AttributeListImpl() { m_pImpl = new AttributeListImpl_impl; } AttributeListImpl::~AttributeListImpl() { delete m_pImpl; } void AttributeListImpl::addAttribute( const OUString &sName , const OUString &sType , const OUString &sValue ) { m_pImpl->vecAttribute.push_back( TagAttribute( sName , sType , sValue ) ); } void AttributeListImpl::clear() { m_pImpl->vecAttribute.clear(); } /** * for external binding * * **/ Reference < XInterface > SAL_CALL OSaxWriterTest_CreateInstance( const Reference < XMultiServiceFactory > & rSMgr ) throw (Exception) { OSaxWriterTest *p = new OSaxWriterTest( rSMgr ); Reference < XInterface > xService = *p; return xService; } OUString OSaxWriterTest_getServiceName( ) throw () { return OUString( RTL_CONSTASCII_USTRINGPARAM("test.com.sun.star.xml.sax.Writer")); } OUString OSaxWriterTest_getImplementationName( ) throw () { return OUString( RTL_CONSTASCII_USTRINGPARAM("test.extensions.xml.sax.Writer")); } Sequence OSaxWriterTest_getSupportedServiceNames( ) throw () { Sequence aRet(1); aRet.getArray()[0] = OSaxWriterTest_getImplementationName( ); return aRet; } void OSaxWriterTest::testInvariant( const OUString& TestName, const Reference < XInterface >& TestObject ) throw ( IllegalArgumentException, RuntimeException) { if( OUString::createFromAscii("com.sun.star.xml.sax.Writer") == TestName ) { Reference< XDocumentHandler > doc( TestObject , UNO_QUERY ); Reference< XExtendedDocumentHandler > ext( TestObject , UNO_QUERY ); Reference< XActiveDataSource > source( TestObject , UNO_QUERY ); ERROR_ASSERT( doc.is() , "XDocumentHandler cannot be queried" ); ERROR_ASSERT( ext.is() , "XExtendedDocumentHandler cannot be queried" ); ERROR_ASSERT( source.is() , "XActiveDataSource cannot be queried" ); } else { BUILD_ERROR( 0 , "wrong test" ); } } sal_Int32 OSaxWriterTest::test( const OUString& TestName, const Reference < XInterface >& TestObject, sal_Int32 hTestHandle) throw ( IllegalArgumentException,RuntimeException) { if( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer")) == TestName ) { try { if( 0 == hTestHandle ) { testInvariant( TestName , TestObject ); } else { Reference< XExtendedDocumentHandler > writer( TestObject , UNO_QUERY ); if( 1 == hTestHandle ) { testSimple( writer ); } else if( 2 == hTestHandle ) { testExceptions( writer ); } else if( 3 == hTestHandle ) { testDTD( writer ); } else if( 4 == hTestHandle ) { testPerformance( writer ); } } } catch( Exception & e ) { OString o = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US ); BUILD_ERROR( 0 , o.getStr() ); } catch( ... ) { BUILD_ERROR( 0 , "unknown exception (Exception is not base class)" ); } hTestHandle ++; if( hTestHandle >= 5) { // all tests finished. hTestHandle = -1; } } else { BUILD_ERROR( 0 , "service not supported by test." ); } return hTestHandle; } sal_Bool OSaxWriterTest::testPassed(void) throw (RuntimeException) { return m_seqErrors.getLength() == 0; } Sequence< OUString > OSaxWriterTest::getErrors(void) throw (RuntimeException) { return m_seqErrors; } Sequence< Any > OSaxWriterTest::getErrorExceptions(void) throw (RuntimeException) { return m_seqExceptions; } Sequence< OUString > OSaxWriterTest::getWarnings(void) throw (RuntimeException) { return m_seqWarnings; } void OSaxWriterTest::writeParagraph( const Reference< XExtendedDocumentHandler > &r , const OUString & s) { int nMax = s.getLength(); int nStart = 0; Sequence seq( s.getLength() ); memcpy( seq.getArray() , s.getStr() , s.getLength() * sizeof( sal_uInt16 ) ); for( int n = 1 ; n < nMax ; n++ ){ if( 32 == seq.getArray()[n] ) { r->allowLineBreak(); r->characters( s.copy( nStart , n - nStart ) ); nStart = n; } } r->allowLineBreak(); r->characters( s.copy( nStart , n - nStart ) ); } void OSaxWriterTest::testSimple( const Reference< XExtendedDocumentHandler > &r ) { OUString testParagraph = OUString( RTL_CONSTASCII_USTRINGPARAM( "Dies ist ein bloeder Test um zu uberpruefen, ob der SAXWriter " "wohl Zeilenumbrueche halbwegs richtig macht oder ob er die Zeile " "bis zum bitteren Ende schreibt." )); OFileWriter *pw = new OFileWriter("output.xml"); AttributeListImpl *pList = new AttributeListImpl; Reference< XAttributeList > rList( (XAttributeList *) pList , UNO_QUERY ); Reference< XOutputStream > ref( ( XOutputStream * ) pw , UNO_QUERY ); Reference< XActiveDataSource > source( r , UNO_QUERY ); ERROR_ASSERT( ref.is() , "no output stream" ); ERROR_ASSERT( source.is() , "no active data source" ); source->setOutputStream( ref ); r->startDocument(); pList->addAttribute( OUString( RTL_CONSTASCII_USTRINGPARAM("Arg1" )), OUString( RTL_CONSTASCII_USTRINGPARAM("CDATA")) , OUString( RTL_CONSTASCII_USTRINGPARAM("bla\n u")) ); pList->addAttribute( OUString( RTL_CONSTASCII_USTRINGPARAM("Arg2")) , OUString( RTL_CONSTASCII_USTRINGPARAM("CDATA")) , OUString( RTL_CONSTASCII_USTRINGPARAM("blub")) ); r->startElement( OUString( RTL_CONSTASCII_USTRINGPARAM("tag1")) , rList ); r->ignorableWhitespace( OUString() ); r->characters( OUString( RTL_CONSTASCII_USTRINGPARAM("huhu")) ); r->ignorableWhitespace( OUString() ); r->startElement( OUString( RTL_CONSTASCII_USTRINGPARAM("hi")) , rList ); r->ignorableWhitespace( OUString() ); // the enpassant must be converted & -> & r->characters( OUString( RTL_CONSTASCII_USTRINGPARAM("ü")) ); // Test added for mib. Tests if errors during conversions occurs r->ignorableWhitespace( OUString() ); sal_Char array[256]; for( sal_Int32 n = 32 ; n < 254 ; n ++ ) { array[n-32] = n; } array[254-32] = 0; r->characters( OStringToOUString( array , RTL_TEXTENCODING_SYMBOL ) ); r->ignorableWhitespace( OUString() ); // '>' must not be converted r->startCDATA(); r->characters( OUString( RTL_CONSTASCII_USTRINGPARAM(">fsfsdf<")) ); r->endCDATA(); r->ignorableWhitespace( OUString() ); writeParagraph( r , testParagraph ); r->ignorableWhitespace( OUString() ); r->comment( OUString( RTL_CONSTASCII_USTRINGPARAM("Dies ist ein Kommentar !")) ); r->ignorableWhitespace( OUString() ); r->startElement( OUString( RTL_CONSTASCII_USTRINGPARAM("emptytagtest")) , rList ); r->endElement( OUString( RTL_CONSTASCII_USTRINGPARAM("emptytagtest")) ); r->endElement( OUString( RTL_CONSTASCII_USTRINGPARAM("hi")) ); r->ignorableWhitespace( OUString() ); r->endElement( OUString( RTL_CONSTASCII_USTRINGPARAM("tag1")) ); r->endDocument(); } void OSaxWriterTest::testExceptions( const Reference< XExtendedDocumentHandler > & r ) { OFileWriter *pw = new OFileWriter("output2.xml"); AttributeListImpl *pList = new AttributeListImpl; Reference< XAttributeList > rList( (XAttributeList *) pList , UNO_QUERY ); Reference< XOutputStream > ref( ( XOutputStream * ) pw , UNO_QUERY ); Reference< XActiveDataSource > source( r , UNO_QUERY ); ERROR_ASSERT( ref.is() , "no output stream" ); ERROR_ASSERT( source.is() , "no active data source" ); source->setOutputStream( ref ); { // startDocument must be called before start element sal_Bool bException = sal_True; try { r->startElement( OUString( RTL_CONSTASCII_USTRINGPARAM("huhu")) , rList ); bException = sal_False; } catch( SAXException &e ) { } ERROR_ASSERT( bException , "expected exception not thrown !" ); } r->startDocument(); r->startElement( OUString( RTL_CONSTASCII_USTRINGPARAM("huhu")) , rList ); r->startCDATA(); { sal_Bool bException = sal_True; try{ r->startElement( OUString( RTL_CONSTASCII_USTRINGPARAM("huhu")) , rList ); bException = sal_False; } catch( SAXException &e ) { } ERROR_ASSERT( bException , "expected exception not thrown !" ); } r->endCDATA(); { sal_Unicode array[] = { 'a' , 'b' , 4 , 9 , 10 }; OUString o( array , 5 ); try { r->characters( o ); ERROR_ASSERT( 0 , "Writer allowed to write forbidden characters" ); } catch( SAXException & e ) { } } r->endElement( OUString( RTL_CONSTASCII_USTRINGPARAM("huhu")) ); r->endDocument(); } void OSaxWriterTest::testDTD(const Reference< XExtendedDocumentHandler > &r ) { OFileWriter *pw = new OFileWriter("outputDTD.xml"); AttributeListImpl *pList = new AttributeListImpl; Reference< XAttributeList > rList( (XAttributeList *) pList , UNO_QUERY ); Reference< XOutputStream > ref( ( XOutputStream * ) pw , UNO_QUERY ); Reference< XActiveDataSource > source( r , UNO_QUERY ); ERROR_ASSERT( ref.is() , "no output stream" ); ERROR_ASSERT( source.is() , "no active data source" ); source->setOutputStream( ref ); r->startDocument(); r->unknown( OUString( RTL_CONSTASCII_USTRINGPARAM("\n")) ); r->startElement( OUString( RTL_CONSTASCII_USTRINGPARAM("huhu")) , rList ); r->endElement( OUString( RTL_CONSTASCII_USTRINGPARAM("huhu")) ); r->endDocument(); } void OSaxWriterTest::testPerformance(const Reference< XExtendedDocumentHandler > &r ) { OFileWriter *pw = new OFileWriter("testPerformance.xml"); AttributeListImpl *pList = new AttributeListImpl; OUString testParagraph = OUString( RTL_CONSTASCII_USTRINGPARAM( "Dies ist ein bloeder Test um zu uberpruefen, ob der SAXWriter " "wohl Zeilenumbrueche halbwegs richtig macht oder ob er die Zeile " "bis zum bitteren Ende schreibt." )); Reference< XAttributeList > rList( (XAttributeList *) pList , UNO_QUERY ); Reference< XOutputStream > ref( ( XOutputStream * ) pw , UNO_QUERY ); Reference< XActiveDataSource > source( r , UNO_QUERY ); ERROR_ASSERT( ref.is() , "no output stream" ); ERROR_ASSERT( source.is() , "no active data source" ); source->setOutputStream( ref ); TimeValue aStartTime, aEndTime; osl_getSystemTime( &aStartTime ); r->startDocument(); // just write a bunch of xml tags ! // for performance testing sal_Int32 i2; OUString huhu( RTL_CONSTASCII_USTRINGPARAM("huhu") ); OUString emptyString; const int ITERATIONS = 125; for( i2 = 0 ; i2 < ITERATIONS ; i2 ++ ) { r->startElement( OUString( RTL_CONSTASCII_USTRINGPARAM("tag") ) + OUString::valueOf( i2 ), rList ); for( sal_Int32 i = 0 ; i < 450 ; i ++ ) { r->ignorableWhitespace( emptyString ); r->startElement( huhu , rList ); r->characters( testParagraph ); r->ignorableWhitespace( emptyString ); r->endElement( huhu ); } } for( i2 = ITERATIONS-1 ; i2 >= 0 ; i2-- ) { r->ignorableWhitespace( emptyString ); r->endElement( OUString( RTL_CONSTASCII_USTRINGPARAM("tag") ) + OUString::valueOf( i2 ) ); } r->endDocument(); osl_getSystemTime( &aEndTime ); double fStart = (double)aStartTime.Seconds + ((double)aStartTime.Nanosec / 1000000000.0); double fEnd = (double)aEndTime.Seconds + ((double)aEndTime.Nanosec / 1000000000.0); printf( "Performance writing : %g s\n" , fEnd - fStart ); } }