xref: /aoo41x/main/sax/test/saxdemo.cxx (revision cdf0e10c)
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