xref: /trunk/main/sax/test/saxdemo.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 //------------------------------------------------------
29 // testcomponent - Loads a service and its testcomponent from dlls performs a test.
30 // Expands the dll-names depending on the actual environment.
31 // Example : testcomponent stardiv.uno.io.Pipe stm
32 //
33 // Therefor the testcode must exist in teststm and the testservice must be named test.stardiv.uno.io.Pipe
34 //
35 
36 #include <stdio.h>
37 #include <vector>
38 
39 #include <com/sun/star/registry/XImplementationRegistration.hpp>
40 #include <com/sun/star/lang/XComponent.hpp>
41 
42 #include <com/sun/star/xml/sax/SAXParseException.hpp>
43 #include <com/sun/star/xml/sax/XParser.hpp>
44 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
45 
46 #include <com/sun/star/io/XOutputStream.hpp>
47 #include <com/sun/star/io/XActiveDataSource.hpp>
48 
49 #include <cppuhelper/servicefactory.hxx>
50 #include <cppuhelper/implbase1.hxx>
51 #include <cppuhelper/implbase3.hxx>
52 
53 #include <vos/dynload.hxx>
54 #include <vos/diagnose.hxx>
55 
56 using namespace ::rtl;
57 using namespace ::std;
58 using namespace ::cppu;
59 using namespace ::com::sun::star::uno;
60 using namespace ::com::sun::star::lang;
61 using namespace ::com::sun::star::registry;
62 using namespace ::com::sun::star::xml::sax;
63 using namespace ::com::sun::star::io;
64 
65 
66 /************
67  * Sequence of bytes -> InputStream
68  ************/
69 class OInputStream : public WeakImplHelper1 < XInputStream >
70 {
71 public:
72     OInputStream( const Sequence< sal_Int8 >&seq ) :
73         m_seq( seq ),
74         nPos( 0 )
75         {}
76 
77 public:
78     virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
79         throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
80         {
81             nBytesToRead = (nBytesToRead > m_seq.getLength() - nPos ) ?
82                 m_seq.getLength() - nPos :
83                 nBytesToRead;
84             aData = Sequence< sal_Int8 > ( &(m_seq.getConstArray()[nPos]) , nBytesToRead );
85             nPos += nBytesToRead;
86             return nBytesToRead;
87         }
88     virtual sal_Int32 SAL_CALL readSomeBytes(
89         ::com::sun::star::uno::Sequence< sal_Int8 >& aData,
90         sal_Int32 nMaxBytesToRead )
91         throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
92         {
93             return readBytes( aData, nMaxBytesToRead );
94         }
95     virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
96         throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
97         {
98             // not implemented
99         }
100     virtual sal_Int32 SAL_CALL available(  )
101         throw(NotConnectedException, IOException, RuntimeException)
102         {
103             return m_seq.getLength() - nPos;
104         }
105     virtual void SAL_CALL closeInput(  )
106         throw(NotConnectedException, IOException, RuntimeException)
107         {
108             // not needed
109         }
110     sal_Int32 nPos;
111     Sequence< sal_Int8> m_seq;
112 };
113 
114 //-------------------------------
115 // Helper : create an input stream from a file
116 //------------------------------
117 Reference< XInputStream > createStreamFromFile(
118     const char *pcFile )
119 {
120     FILE *f = fopen( pcFile , "rb" );
121     Reference<  XInputStream >  r;
122 
123     if( f ) {
124         fseek( f , 0 , SEEK_END );
125         int nLength = ftell( f );
126         fseek( f , 0 , SEEK_SET );
127 
128         Sequence<sal_Int8> seqIn(nLength);
129         fread( seqIn.getArray() , nLength , 1 , f );
130 
131         r = Reference< XInputStream > ( new OInputStream( seqIn ) );
132         fclose( f );
133     }
134     return r;
135 }
136 
137 //-----------------------------------------
138 // The document handler, which is needed for the saxparser
139 // The Documenthandler for reading sax
140 //-----------------------------------------
141 class TestDocumentHandler :
142     public WeakImplHelper3< XExtendedDocumentHandler , XEntityResolver , XErrorHandler >
143 {
144 public:
145     TestDocumentHandler(  )
146     {
147     }
148 
149 public: // Error handler
150     virtual void SAL_CALL error(const Any& aSAXParseException) throw (SAXException, RuntimeException)
151     {
152         printf( "Error !\n" );
153         throw  SAXException(
154             OUString( RTL_CONSTASCII_USTRINGPARAM("error from error handler")) ,
155             Reference < XInterface >() ,
156             aSAXParseException );
157     }
158     virtual void SAL_CALL fatalError(const Any& aSAXParseException) throw (SAXException, RuntimeException)
159     {
160         printf( "Fatal Error !\n" );
161     }
162     virtual void SAL_CALL warning(const Any& aSAXParseException) throw (SAXException, RuntimeException)
163     {
164         printf( "Warning !\n" );
165     }
166 
167 
168 public: // ExtendedDocumentHandler
169 
170     virtual void SAL_CALL startDocument(void) throw (SAXException, RuntimeException)
171     {
172         m_iElementCount = 0;
173         m_iAttributeCount = 0;
174         m_iWhitespaceCount =0;
175         m_iCharCount=0;
176         printf( "document started\n" );
177     }
178     virtual void SAL_CALL endDocument(void) throw (SAXException, RuntimeException)
179     {
180         printf( "document finished\n" );
181         printf( "(ElementCount %d),(AttributeCount %d),(WhitespaceCount %d),(CharCount %d)\n",
182                 m_iElementCount, m_iAttributeCount, m_iWhitespaceCount , m_iCharCount );
183 
184     }
185     virtual void SAL_CALL startElement(const OUString& aName,
186                               const Reference< XAttributeList > & xAttribs)
187         throw (SAXException,RuntimeException)
188     {
189         m_iElementCount ++;
190         m_iAttributeCount += xAttribs->getLength();
191     }
192 
193     virtual void SAL_CALL endElement(const OUString& aName) throw (SAXException,RuntimeException)
194     {
195         // ignored
196     }
197 
198     virtual void SAL_CALL characters(const OUString& aChars) throw (SAXException,RuntimeException)
199     {
200         m_iCharCount += aChars.getLength();
201     }
202     virtual void SAL_CALL ignorableWhitespace(const OUString& aWhitespaces) throw (SAXException,RuntimeException)
203     {
204         m_iWhitespaceCount += aWhitespaces.getLength();
205     }
206 
207     virtual void SAL_CALL processingInstruction(const OUString& aTarget, const OUString& aData) throw (SAXException,RuntimeException)
208     {
209         // ignored
210     }
211 
212     virtual void SAL_CALL setDocumentLocator(const Reference< XLocator> & xLocator)
213         throw (SAXException,RuntimeException)
214     {
215         // ignored
216     }
217 
218     virtual InputSource SAL_CALL resolveEntity(
219         const OUString& sPublicId,
220         const OUString& sSystemId)
221         throw (SAXException,RuntimeException)
222     {
223         InputSource source;
224         source.sSystemId = sSystemId;
225         source.sPublicId = sPublicId;
226 
227         source.aInputStream = createStreamFromFile(
228             OUStringToOString( sSystemId , RTL_TEXTENCODING_ASCII_US) );
229 
230         return source;
231     }
232 
233     virtual void SAL_CALL startCDATA(void) throw (SAXException,RuntimeException)
234     {
235     }
236     virtual void SAL_CALL endCDATA(void) throw (SAXException,RuntimeException)
237     {
238     }
239     virtual void SAL_CALL comment(const OUString& sComment) throw (SAXException,RuntimeException)
240     {
241     }
242     virtual void SAL_CALL unknown(const OUString& sString) throw (SAXException,RuntimeException)
243     {
244     }
245 
246     virtual void SAL_CALL allowLineBreak( void) throw (SAXException, RuntimeException )
247     {
248 
249     }
250 
251 public:
252     int m_iElementCount;
253     int m_iAttributeCount;
254     int m_iWhitespaceCount;
255     int m_iCharCount;
256 };
257 
258 //--------------------------------------
259 // helper implementation for writing
260 // implements an XAttributeList
261 //-------------------------------------
262 struct AttributeListImpl_impl;
263 class AttributeListImpl : public WeakImplHelper1< XAttributeList >
264 {
265 public:
266     AttributeListImpl();
267     AttributeListImpl( const AttributeListImpl & );
268     ~AttributeListImpl();
269 
270 public:
271     virtual sal_Int16 SAL_CALL getLength(void) throw  (RuntimeException);
272     virtual OUString SAL_CALL getNameByIndex(sal_Int16 i) throw  (RuntimeException);
273     virtual OUString SAL_CALL getTypeByIndex(sal_Int16 i) throw  (RuntimeException);
274     virtual OUString SAL_CALL getTypeByName(const OUString& aName) throw  (RuntimeException);
275     virtual OUString SAL_CALL getValueByIndex(sal_Int16 i) throw  (RuntimeException);
276     virtual OUString SAL_CALL getValueByName(const OUString& aName) throw  (RuntimeException);
277 
278 public:
279     void addAttribute( const OUString &sName ,
280                        const OUString &sType ,
281                        const OUString &sValue );
282     void clear();
283 
284 private:
285     struct AttributeListImpl_impl *m_pImpl;
286 };
287 
288 
289 struct TagAttribute
290 {
291     TagAttribute(){}
292     TagAttribute( const OUString &sName,
293                   const OUString &sType ,
294                   const OUString &sValue )
295     {
296         this->sName     = sName;
297         this->sType     = sType;
298         this->sValue    = sValue;
299     }
300 
301     OUString sName;
302     OUString sType;
303     OUString sValue;
304 };
305 
306 struct AttributeListImpl_impl
307 {
308     AttributeListImpl_impl()
309     {
310         // performance improvement during adding
311         vecAttribute.reserve(20);
312     }
313     vector<struct TagAttribute> vecAttribute;
314 };
315 
316 
317 
318 sal_Int16 AttributeListImpl::getLength(void) throw  (RuntimeException)
319 {
320     return m_pImpl->vecAttribute.size();
321 }
322 
323 
324 AttributeListImpl::AttributeListImpl( const AttributeListImpl &r )
325 {
326     m_pImpl = new AttributeListImpl_impl;
327     *m_pImpl = *(r.m_pImpl);
328 }
329 
330 OUString AttributeListImpl::getNameByIndex(sal_Int16 i) throw  (RuntimeException)
331 {
332     if( i < m_pImpl->vecAttribute.size() ) {
333         return m_pImpl->vecAttribute[i].sName;
334     }
335     return OUString();
336 }
337 
338 
339 OUString AttributeListImpl::getTypeByIndex(sal_Int16 i) throw  (RuntimeException)
340 {
341     if( i < m_pImpl->vecAttribute.size() ) {
342         return m_pImpl->vecAttribute[i].sType;
343     }
344     return OUString();
345 }
346 
347 OUString AttributeListImpl::getValueByIndex(sal_Int16 i) throw  (RuntimeException)
348 {
349     if( i < m_pImpl->vecAttribute.size() ) {
350         return m_pImpl->vecAttribute[i].sValue;
351     }
352     return OUString();
353 
354 }
355 
356 OUString AttributeListImpl::getTypeByName( const OUString& sName ) throw  (RuntimeException)
357 {
358     vector<struct TagAttribute>::iterator ii = m_pImpl->vecAttribute.begin();
359 
360     for( ; ii != m_pImpl->vecAttribute.end() ; ii ++ ) {
361         if( (*ii).sName == sName ) {
362             return (*ii).sType;
363         }
364     }
365     return OUString();
366 }
367 
368 OUString AttributeListImpl::getValueByName(const OUString& sName) throw  (RuntimeException)
369 {
370     vector<struct TagAttribute>::iterator ii = m_pImpl->vecAttribute.begin();
371 
372     for( ; ii != m_pImpl->vecAttribute.end() ; ii ++ ) {
373         if( (*ii).sName == sName ) {
374             return (*ii).sValue;
375         }
376     }
377     return OUString();
378 }
379 
380 
381 
382 AttributeListImpl::AttributeListImpl()
383 {
384     m_pImpl = new AttributeListImpl_impl;
385 }
386 
387 
388 
389 AttributeListImpl::~AttributeListImpl()
390 {
391     delete m_pImpl;
392 }
393 
394 
395 void AttributeListImpl::addAttribute(   const OUString &sName ,
396                                         const OUString &sType ,
397                                         const OUString &sValue )
398 {
399     m_pImpl->vecAttribute.push_back( TagAttribute( sName , sType , sValue ) );
400 }
401 
402 void AttributeListImpl::clear()
403 {
404     m_pImpl->vecAttribute.clear();
405 }
406 
407 
408 //--------------------------------------
409 // helper function for writing
410 // ensures that linebreaks are inserted
411 // when writing a long text.
412 // Note: this implementation may be a bit slow,
413 // but it shows, how the SAX-Writer handles the allowLineBreak calls.
414 //--------------------------------------
415 void writeParagraphHelper(
416     const  Reference< XExtendedDocumentHandler > &r ,
417     const OUString & s)
418 {
419     int nMax = s.getLength();
420     int nStart = 0;
421 
422     Sequence<sal_uInt16> seq( s.getLength() );
423     memcpy( seq.getArray() , s.getStr() , s.getLength() * sizeof( sal_uInt16 ) );
424 
425     for( int n = 1 ; n < nMax ; n++ ){
426         if( 32 == seq.getArray()[n] ) {
427             r->allowLineBreak();
428             r->characters( s.copy( nStart , n - nStart ) );
429             nStart = n;
430         }
431     }
432     r->allowLineBreak();
433     r->characters( s.copy( nStart , n - nStart ) );
434 }
435 
436 
437 //---------------------------------
438 // helper implementation for SAX-Writer
439 // writes data to a file
440 //--------------------------------
441 class OFileWriter :
442         public WeakImplHelper1< XOutputStream >
443 {
444 public:
445     OFileWriter( char *pcFile ) { strncpy( m_pcFile , pcFile, 256 - 1 ); m_f = 0; }
446 
447 
448 public:
449     virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData)
450         throw  (NotConnectedException, BufferSizeExceededException, RuntimeException);
451     virtual void SAL_CALL flush(void)
452         throw  (NotConnectedException, BufferSizeExceededException, RuntimeException);
453     virtual void SAL_CALL closeOutput(void)
454         throw  (NotConnectedException, BufferSizeExceededException, RuntimeException);
455 private:
456     char m_pcFile[256];
457     FILE *m_f;
458 };
459 
460 
461 void OFileWriter::writeBytes(const Sequence< sal_Int8 >& aData)
462     throw  (NotConnectedException, BufferSizeExceededException, RuntimeException)
463 {
464     if( ! m_f ) {
465         m_f = fopen( m_pcFile , "w" );
466     }
467 
468     fwrite( aData.getConstArray() , 1 , aData.getLength() , m_f );
469 }
470 
471 
472 void OFileWriter::flush(void)
473     throw  (NotConnectedException, BufferSizeExceededException, RuntimeException)
474 {
475     fflush( m_f );
476 }
477 
478 void OFileWriter::closeOutput(void)
479     throw  (NotConnectedException, BufferSizeExceededException, RuntimeException)
480 {
481     fclose( m_f );
482     m_f = 0;
483 }
484 
485 
486 
487 // Needed to switch on solaris threads
488 #ifdef SOLARIS
489 extern "C" void ChangeGlobalInit();
490 #endif
491 int main (int argc, char **argv)
492 {
493 
494     if( argc < 3) {
495         printf( "usage : saxdemo inputfile outputfile\n" );
496         exit( 0 );
497     }
498 #ifdef SOLARIS
499     // switch on threads in solaris
500     ChangeGlobalInit();
501 #endif
502 
503     // create service manager
504     Reference< XMultiServiceFactory > xSMgr = createRegistryServiceFactory(
505         OUString( RTL_CONSTASCII_USTRINGPARAM( "applicat.rdb" )) );
506 
507     Reference < XImplementationRegistration > xReg;
508     try
509     {
510         // Create registration service
511         Reference < XInterface > x = xSMgr->createInstance(
512             OUString::createFromAscii( "com.sun.star.registry.ImplementationRegistration" ) );
513         xReg = Reference<  XImplementationRegistration > ( x , UNO_QUERY );
514     }
515     catch( Exception & ) {
516         printf( "Couldn't create ImplementationRegistration service\n" );
517         exit(1);
518     }
519 
520     OString sTestName;
521     try
522     {
523         // Load dll for the tested component
524         OUString aDllName =
525             OUString::createFromAscii( "sax.uno" SAL_DLLEXTENSION );
526         xReg->registerImplementation(
527             OUString::createFromAscii( "com.sun.star.loader.SharedLibrary" ),
528             aDllName,
529             Reference< XSimpleRegistry > ()  );
530     }
531     catch( Exception &e ) {
532         printf( "Couldn't reach sax dll\n" );
533         printf( "%s\n" , OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US ).getStr() );
534 
535         exit(1);
536     }
537 
538 
539     //--------------------------------
540     // parser demo
541     // read xml from a file and count elements
542     //--------------------------------
543     Reference< XInterface > x = xSMgr->createInstance(
544         OUString::createFromAscii( "com.sun.star.xml.sax.Parser" ) );
545     if( x.is() )
546     {
547         Reference< XParser > rParser( x , UNO_QUERY );
548 
549         // create and connect the document handler to the parser
550         TestDocumentHandler *pDocHandler = new TestDocumentHandler( );
551 
552         Reference < XDocumentHandler >  rDocHandler( (XDocumentHandler *) pDocHandler );
553         Reference< XEntityResolver > rEntityResolver( (XEntityResolver *) pDocHandler );
554 
555         rParser->setDocumentHandler( rDocHandler );
556         rParser->setEntityResolver( rEntityResolver );
557 
558         // create the input stream
559         InputSource source;
560         source.aInputStream = createStreamFromFile( argv[1] );
561         source.sSystemId    = OUString::createFromAscii( argv[1] );
562 
563         try
564         {
565             // start parsing
566             rParser->parseStream( source );
567         }
568 
569         catch( Exception & e )
570         {
571             OString o1 = OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8 );
572             printf( "Exception during parsing : %s\n" ,  o1.getStr() );
573         }
574     }
575     else
576     {
577         printf( "couln't create sax-parser component\n" );
578     }
579 
580 
581     //----------------------
582     // The SAX-Writer demo
583     //----------------------
584     x= xSMgr->createInstance( OUString::createFromAscii( "com.sun.star.xml.sax.Writer" ) );
585     if( x.is() )
586     {
587         printf( "start writing to %s\n" , argv[2] );
588 
589         OFileWriter *pw = new OFileWriter( argv[2] );
590         Reference< XActiveDataSource > source( x , UNO_QUERY );
591         source->setOutputStream( Reference< XOutputStream> ( (XOutputStream*) pw ) );
592 
593         AttributeListImpl *pList = new AttributeListImpl;
594         Reference< XAttributeList > rList( (XAttributeList *) pList );
595 
596         Reference< XExtendedDocumentHandler > r( x , UNO_QUERY );
597         r->startDocument();
598 
599         pList->addAttribute( OUString( RTL_CONSTASCII_USTRINGPARAM("Arg1" )),
600                              OUString( RTL_CONSTASCII_USTRINGPARAM("CDATA")) ,
601                              OUString( RTL_CONSTASCII_USTRINGPARAM("foo\n   u")) );
602         pList->addAttribute( OUString( RTL_CONSTASCII_USTRINGPARAM("Arg2")) ,
603                              OUString( RTL_CONSTASCII_USTRINGPARAM("CDATA")) ,
604                              OUString( RTL_CONSTASCII_USTRINGPARAM("foo2")) );
605 
606         r->startElement( OUString( RTL_CONSTASCII_USTRINGPARAM("tag1"))  , rList );
607         // tells the writer to insert a linefeed
608         r->ignorableWhitespace( OUString() );
609 
610         r->characters( OUString( RTL_CONSTASCII_USTRINGPARAM("huhu")) );
611         r->ignorableWhitespace( OUString() );
612 
613         r->startElement( OUString( RTL_CONSTASCII_USTRINGPARAM("hi")) , rList );
614         r->ignorableWhitespace( OUString() );
615 
616         // the enpassant must be converted & -> &amp;
617         r->characters( OUString( RTL_CONSTASCII_USTRINGPARAM("&#252;")) );
618         r->ignorableWhitespace( OUString() );
619 
620         // '>' must not be converted
621         r->startCDATA();
622         r->characters( OUString( RTL_CONSTASCII_USTRINGPARAM(" > foo < "))  );
623         r->endCDATA();
624         r->ignorableWhitespace( OUString() );
625 
626         OUString testParagraph = OUString( RTL_CONSTASCII_USTRINGPARAM(
627             "This is only a test to check, if the writer inserts line feeds "
628             "if needed or if the writer puts the whole text into one line." ));
629         writeParagraphHelper( r , testParagraph );
630 
631         r->ignorableWhitespace( OUString() );
632         r->comment( OUString( RTL_CONSTASCII_USTRINGPARAM("This is a comment !")) );
633         r->ignorableWhitespace( OUString() );
634 
635         r->startElement( OUString( RTL_CONSTASCII_USTRINGPARAM("emptytagtest"))  , rList );
636         r->endElement( OUString( RTL_CONSTASCII_USTRINGPARAM("emptytagtest")) );
637         r->ignorableWhitespace( OUString() );
638 
639         r->endElement( OUString( RTL_CONSTASCII_USTRINGPARAM("hi")) );
640         r->ignorableWhitespace( OUString() );
641 
642         r->endElement( OUString( RTL_CONSTASCII_USTRINGPARAM("tag1")) );
643         r->endDocument();
644 
645         printf( "finished writing\n" );
646     }
647     else
648     {
649         printf( "couln't create sax-writer component\n" );
650     }
651 }
652