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