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