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 & -> &
590 r->characters( OUString( "ü") );
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