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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_xmlhelp.hxx"
26
27 #define WORKAROUND_98119
28
29 #ifdef WORKAROUND_98119
30 #include "bufferedinputstream.hxx"
31 #endif
32
33 #include <string.h>
34 #ifndef _VOS_DIAGNOSE_HXX_
35 #include <vos/diagnose.hxx>
36 #endif
37 #include <osl/thread.h>
38 #include <rtl/memory.h>
39 #include <osl/file.hxx>
40 #include <cppuhelper/weak.hxx>
41 #include <cppuhelper/queryinterface.hxx>
42 #include <comphelper/processfactory.hxx>
43 #include <rtl/uri.hxx>
44 #include <rtl/ustrbuf.hxx>
45 #include <libxslt/xslt.h>
46 #include <libxslt/transform.h>
47 #include <libxslt/xsltutils.h>
48 #include "db.hxx"
49 #include <com/sun/star/io/XActiveDataSink.hpp>
50 #include <com/sun/star/io/XInputStream.hpp>
51 #include <com/sun/star/io/XSeekable.hpp>
52 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
53 #include <com/sun/star/ucb/OpenMode.hpp>
54 #include <com/sun/star/ucb/XCommandProcessor.hpp>
55 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
56 #include <com/sun/star/ucb/XContentIdentifier.hpp>
57 #include <com/sun/star/ucb/XContentProvider.hpp>
58 #include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
59 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
60 #include <com/sun/star/beans/XPropertySet.hpp>
61
62 #include "urlparameter.hxx"
63 #include "databases.hxx"
64
65 namespace chelp {
66
ascii_isDigit(sal_Unicode ch)67 inline bool ascii_isDigit( sal_Unicode ch )
68 {
69 return ((ch >= 0x0030) && (ch <= 0x0039));
70 }
71
ascii_isLetter(sal_Unicode ch)72 inline bool ascii_isLetter( sal_Unicode ch )
73 {
74 return ( ( (ch >= 0x0041) && (ch <= 0x005A) ) ||
75 ( (ch >= 0x0061) && (ch <= 0x007A) ) );
76 }
77
isLetterOrDigit(sal_Unicode ch)78 inline bool isLetterOrDigit( sal_Unicode ch )
79 {
80 return ascii_isLetter( ch ) || ascii_isDigit( ch );
81 }
82
83 }
84
85 using namespace cppu;
86 using namespace com::sun::star::io;
87 using namespace com::sun::star::uno;
88 using namespace com::sun::star::lang;
89 using namespace com::sun::star::ucb;
90 using namespace com::sun::star::beans;
91 using namespace com::sun::star::container;
92 using namespace chelp;
93
94
URLParameter(const rtl::OUString & aURL,Databases * pDatabases)95 URLParameter::URLParameter( const rtl::OUString& aURL,
96 Databases* pDatabases )
97 throw( com::sun::star::ucb::IllegalIdentifierException )
98 : m_pDatabases( pDatabases ),
99 m_aURL( aURL )
100 {
101 init( false );
102 parse();
103 }
104
105
isErrorDocument()106 bool URLParameter::isErrorDocument()
107 {
108 bool bErrorDoc = false;
109
110 if( isFile() )
111 {
112 Reference< XHierarchicalNameAccess > xNA =
113 m_pDatabases->findJarFileForPath( get_jar(), get_language(), get_path() );
114 bErrorDoc = !xNA.is();
115 }
116
117 return bErrorDoc;
118 }
119
120
getByName(const char * par)121 rtl::OString URLParameter::getByName( const char* par )
122 {
123 rtl::OUString val;
124
125 if( strcmp( par,"Program" ) == 0 )
126 val = get_program();
127 else if( strcmp( par,"Database" ) == 0 )
128 val = get_module();
129 else if( strcmp( par,"DatabasePar" ) == 0 )
130 val = get_dbpar();
131 else if( strcmp( par,"Id" ) == 0 )
132 val = get_id();
133 else if( strcmp( par,"Path" ) == 0 )
134 val = get_path();
135 else if( strcmp( par,"Language" ) == 0 )
136 val = get_language();
137 else if( strcmp( par,"System" ) == 0 )
138 val = get_system();
139 else if( strcmp( par,"HelpPrefix" ) == 0 )
140 val = get_prefix();
141
142 return rtl::OString( val.getStr(),val.getLength(),RTL_TEXTENCODING_UTF8 );
143 }
144
145
get_id()146 rtl::OUString URLParameter::get_id()
147 {
148 if( m_aId.compareToAscii("start") == 0 )
149 { // module is set
150 StaticModuleInformation* inf =
151 m_pDatabases->getStaticInformationForModule( get_module(),
152 get_language() );
153 if( inf )
154 m_aId = inf->get_id();
155
156 m_bStart = true;
157 }
158
159 return m_aId;
160 }
161
get_tag()162 rtl::OUString URLParameter::get_tag()
163 {
164 if( isFile() )
165 return get_the_tag();
166 else
167 return m_aTag;
168 }
169
170
get_title()171 rtl::OUString URLParameter::get_title()
172 {
173 if( isFile() )
174 return get_the_title();
175 else if( m_aModule.compareToAscii("") != 0 )
176 {
177 StaticModuleInformation* inf =
178 m_pDatabases->getStaticInformationForModule( get_module(),
179 get_language() );
180 if( inf )
181 m_aTitle = inf->get_title();
182 }
183 else // This must be the root
184 m_aTitle = rtl::OUString::createFromAscii("root");
185
186 return m_aTitle;
187 }
188
189
get_language()190 rtl::OUString URLParameter::get_language()
191 {
192 if( m_aLanguage.getLength() == 0 )
193 return m_aDefaultLanguage;
194
195 return m_aLanguage;
196 }
197
198
get_program()199 rtl::OUString URLParameter::get_program()
200 {
201 if( ! m_aProgram.getLength() )
202 {
203 StaticModuleInformation* inf =
204 m_pDatabases->getStaticInformationForModule( get_module(),
205 get_language() );
206 if( inf )
207 m_aProgram = inf->get_program();
208 }
209 return m_aProgram;
210 }
211
212
init(bool bDefaultLanguageIsInitialized)213 void URLParameter::init( bool bDefaultLanguageIsInitialized )
214 {
215 (void)bDefaultLanguageIsInitialized;
216
217 m_bHelpDataFileRead = false;
218 m_bStart = false;
219 m_bUseDB = true;
220 m_nHitCount = 100; // The default maximum hitcount
221 }
222
223
get_the_tag()224 rtl::OUString URLParameter::get_the_tag()
225 {
226 if(m_bUseDB) {
227 if( ! m_bHelpDataFileRead )
228 readHelpDataFile();
229
230 m_bHelpDataFileRead = true;
231
232 return m_aTag;
233 }
234 else
235 return rtl::OUString();
236 }
237
238
239
get_the_path()240 rtl::OUString URLParameter::get_the_path()
241 {
242 if(m_bUseDB) {
243 if( ! m_bHelpDataFileRead )
244 readHelpDataFile();
245 m_bHelpDataFileRead = true;
246
247 return m_aPath;
248 }
249 else
250 return get_id();
251 }
252
253
254
get_the_title()255 rtl::OUString URLParameter::get_the_title()
256 {
257 if(m_bUseDB) {
258 if( ! m_bHelpDataFileRead )
259 readHelpDataFile();
260 m_bHelpDataFileRead = true;
261
262 return m_aTitle;
263 }
264 else
265 return rtl::OUString();
266 }
267
268
get_the_jar()269 rtl::OUString URLParameter::get_the_jar()
270 {
271 if(m_bUseDB) {
272 if( ! m_bHelpDataFileRead )
273 readHelpDataFile();
274 m_bHelpDataFileRead = true;
275
276 return m_aJar;
277 }
278 else
279 return get_module() + rtl::OUString::createFromAscii(".jar");
280 }
281
282
283
284
readHelpDataFile()285 void URLParameter::readHelpDataFile()
286 {
287 static rtl::OUString aQuestionMark( rtl::OUString::createFromAscii( "?" ) );
288
289 if( get_id().compareToAscii("") == 0 )
290 return;
291
292 rtl::OUString aModule = get_module();
293 rtl::OUString aLanguage = get_language();
294
295 DataBaseIterator aDbIt( *m_pDatabases, aModule, aLanguage, false );
296 bool bSuccess = false;
297
298 int nSize = 0;
299 const sal_Char* pData = NULL;
300
301 helpdatafileproxy::HDFData aHDFData;
302 rtl::OUString aExtensionPath;
303 rtl::OUString aExtensionRegistryPath;
304 while( true )
305 {
306 helpdatafileproxy::Hdf* pHdf = aDbIt.nextHdf( &aExtensionPath, &aExtensionRegistryPath );
307 if( !pHdf )
308 break;
309
310 rtl::OString keyStr( m_aId.getStr(),m_aId.getLength(),RTL_TEXTENCODING_UTF8 );
311
312 bSuccess = pHdf->getValueForKey( keyStr, aHDFData );
313 if( bSuccess )
314 {
315 nSize = aHDFData.getSize();
316 pData = aHDFData.getData();
317 break;
318 }
319 }
320
321 if( bSuccess )
322 {
323 DbtToStringConverter converter( pData, nSize );
324 m_aTitle = converter.getTitle();
325 m_pDatabases->replaceName( m_aTitle );
326 m_aPath = converter.getFile();
327 m_aJar = converter.getDatabase();
328 if( aExtensionPath.getLength() > 0 )
329 {
330 rtl::OUStringBuffer aExtendedJarStrBuf;
331 aExtendedJarStrBuf.append( aQuestionMark );
332 aExtendedJarStrBuf.append( aExtensionPath );
333 aExtendedJarStrBuf.append( aQuestionMark );
334 aExtendedJarStrBuf.append( m_aJar );
335 m_aJar = aExtendedJarStrBuf.makeStringAndClear();
336 m_aExtensionRegistryPath = aExtensionRegistryPath;
337 }
338 m_aTag = converter.getHash();
339 }
340 }
341
342
343
344 // Class encapsulating the transformation of the XInputStream to XHTML
345
346
347 class InputStreamTransformer
348 : public OWeakObject,
349 public XInputStream,
350 public XSeekable
351 {
352 public:
353
354 InputStreamTransformer( URLParameter* urlParam,
355 Databases* pDatatabases,
356 bool isRoot = false );
357
358 ~InputStreamTransformer();
359
360 virtual Any SAL_CALL queryInterface( const Type& rType ) throw( RuntimeException );
361 virtual void SAL_CALL acquire( void ) throw();
362 virtual void SAL_CALL release( void ) throw();
363
364 virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData,sal_Int32 nBytesToRead )
365 throw( NotConnectedException,
366 BufferSizeExceededException,
367 IOException,
368 RuntimeException);
369
370 virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData,sal_Int32 nMaxBytesToRead )
371 throw( NotConnectedException,
372 BufferSizeExceededException,
373 IOException,
374 RuntimeException);
375
376 virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) throw( NotConnectedException,
377 BufferSizeExceededException,
378 IOException,
379 RuntimeException );
380
381 virtual sal_Int32 SAL_CALL available( void ) throw( NotConnectedException,
382 IOException,
383 RuntimeException );
384
385 virtual void SAL_CALL closeInput( void ) throw( NotConnectedException,
386 IOException,
387 RuntimeException );
388
389 virtual void SAL_CALL seek( sal_Int64 location ) throw( IllegalArgumentException,
390 IOException,
391 RuntimeException );
392
393 virtual sal_Int64 SAL_CALL getPosition( void ) throw( IOException,RuntimeException );
394
395 virtual sal_Int64 SAL_CALL getLength( void ) throw( IOException,RuntimeException );
396
397 void addToBuffer( const char* buffer,int len );
398
getData() const399 sal_Int8* getData() const { return (sal_Int8*) buffer; }
400
getLen() const401 sal_Int32 getLen() const { return sal_Int32( len ); }
402
403 private:
404
405 osl::Mutex m_aMutex;
406
407 int len,pos;
408 char *buffer;
409 };
410
411
412
open(const Reference<XMultiServiceFactory> & rxSMgr,const Command & aCommand,sal_Int32 CommandId,const Reference<XCommandEnvironment> & Environment,const Reference<XOutputStream> & xDataSink)413 void URLParameter::open( const Reference< XMultiServiceFactory >& rxSMgr,
414 const Command& aCommand,
415 sal_Int32 CommandId,
416 const Reference< XCommandEnvironment >& Environment,
417 const Reference< XOutputStream >& xDataSink )
418 {
419 (void)rxSMgr;
420 (void)aCommand;
421 (void)CommandId;
422 (void)Environment;
423
424 if( ! xDataSink.is() )
425 return;
426
427 if( isPicture() )
428 {
429 Reference< XInputStream > xStream;
430 Reference< XHierarchicalNameAccess > xNA =
431 m_pDatabases->jarFile( rtl::OUString::createFromAscii( "picture.jar" ),
432 get_language() );
433
434 rtl::OUString path = get_path();
435 if( xNA.is() )
436 {
437 try
438 {
439 Any aEntry = xNA->getByHierarchicalName( path );
440 Reference< XActiveDataSink > xSink;
441 if( ( aEntry >>= xSink ) && xSink.is() )
442 xStream = xSink->getInputStream();
443 }
444 catch ( NoSuchElementException & )
445 {
446 }
447 }
448 if( xStream.is() )
449 {
450 sal_Int32 ret;
451 Sequence< sal_Int8 > aSeq( 4096 );
452 while( true )
453 {
454 try
455 {
456 ret = xStream->readBytes( aSeq,4096 );
457 xDataSink->writeBytes( aSeq );
458 if( ret < 4096 )
459 break;
460 }
461 catch( const Exception& )
462 {
463 break;
464 }
465 }
466 }
467 }
468 else
469 {
470 // a standard document or else an active help text, plug in the new input stream
471 InputStreamTransformer* p = new InputStreamTransformer( this,m_pDatabases,isRoot() );
472 try
473 {
474 xDataSink->writeBytes( Sequence< sal_Int8 >( p->getData(),p->getLen() ) );
475 }
476 catch( const Exception& )
477 {
478 }
479 delete p;
480 }
481 xDataSink->closeOutput();
482 }
483
484
485
open(const Reference<XMultiServiceFactory> & rxSMgr,const Command & aCommand,sal_Int32 CommandId,const Reference<XCommandEnvironment> & Environment,const Reference<XActiveDataSink> & xDataSink)486 void URLParameter::open( const Reference< XMultiServiceFactory >& rxSMgr,
487 const Command& aCommand,
488 sal_Int32 CommandId,
489 const Reference< XCommandEnvironment >& Environment,
490 const Reference< XActiveDataSink >& xDataSink )
491 {
492 (void)rxSMgr;
493 (void)aCommand;
494 (void)CommandId;
495 (void)Environment;
496
497 if( isPicture() )
498 {
499 Reference< XInputStream > xStream;
500 Reference< XHierarchicalNameAccess > xNA =
501 m_pDatabases->jarFile( rtl::OUString::createFromAscii( "picture.jar" ),
502 get_language() );
503
504 rtl::OUString path = get_path();
505 if( xNA.is() )
506 {
507 try
508 {
509 Any aEntry = xNA->getByHierarchicalName( path );
510 Reference< XActiveDataSink > xSink;
511 if( ( aEntry >>= xSink ) && xSink.is() )
512 xStream = xSink->getInputStream();
513 }
514 catch ( NoSuchElementException & )
515 {
516 }
517 }
518 #ifdef WORKAROUND_98119
519 xDataSink->setInputStream( turnToSeekable(xStream) );
520 #else
521 xDataSink->setInputStream( xStream );
522 #endif
523 }
524 else
525 // a standard document or else an active help text, plug in the new input stream
526 xDataSink->setInputStream( new InputStreamTransformer( this,m_pDatabases,isRoot() ) );
527 }
528
529
530 // #include <stdio.h>
531
parse()532 void URLParameter::parse() throw( com::sun::star::ucb::IllegalIdentifierException )
533 {
534 // fprintf(stdout,"url send to xmlhelp: %s\n",(rtl::OUStringToOString(m_aURL,RTL_TEXTENCODING_UTF8).getStr()));
535 m_aExpr = m_aURL;
536
537 sal_Int32 lstIdx = m_aExpr.lastIndexOf( sal_Unicode( '#' ) );
538 if( lstIdx != -1 )
539 m_aExpr = m_aExpr.copy( 0,lstIdx );
540
541 if( ! scheme() ||
542 ! name( module() ) ||
543 ! query() ||
544 ! m_aLanguage.getLength() ||
545 ! m_aSystem.getLength() )
546 throw com::sun::star::ucb::IllegalIdentifierException();
547 }
548
549
scheme()550 bool URLParameter::scheme()
551 {
552 // Correct extension help links as sometimes the
553 // module is missing resulting in a misformed URL
554 if( m_aExpr.compareToAscii( "vnd.sun.star.help:///", 21 ) == 0 )
555 {
556 sal_Int32 nLen = m_aExpr.getLength();
557 rtl::OUString aLastStr = m_aExpr.copy( nLen - 6 );
558 if( aLastStr.compareToAscii( "DbPAR=" ) == 0 )
559 {
560 rtl::OUString aNewExpr = m_aExpr.copy( 0, 20 );
561 rtl::OUString aSharedStr = rtl::OUString::createFromAscii( "shared" );
562 aNewExpr += aSharedStr;
563 aNewExpr += m_aExpr.copy( 20 );
564 aNewExpr += aSharedStr;
565 m_aExpr = aNewExpr;
566 }
567 }
568
569 for( sal_Int32 nPrefixLen = 20 ; nPrefixLen >= 18 ; --nPrefixLen )
570 {
571 if( m_aExpr.compareToAscii( "vnd.sun.star.help://", nPrefixLen ) == 0 )
572 {
573 m_aExpr = m_aExpr.copy( nPrefixLen );
574 return true;
575 }
576 }
577 return false;
578 }
579
580
module()581 bool URLParameter::module()
582 {
583 sal_Int32 idx = 0,length = m_aExpr.getLength();
584
585 while( idx < length && isLetterOrDigit( (m_aExpr.getStr())[idx] ) )
586 ++idx;
587
588 if( idx != 0 )
589 {
590 m_aModule = m_aExpr.copy( 0,idx );
591 m_aExpr = m_aExpr.copy( idx );
592 return true;
593 }
594 else
595 return false;
596 }
597
598
599
name(bool modulePresent)600 bool URLParameter::name( bool modulePresent )
601 {
602 // if modulepresent, a name may be present, but must not
603
604 sal_Int32 length = m_aExpr.getLength();
605
606 if( length != 0 && (m_aExpr.getStr())[0] == sal_Unicode( '/' ) )
607 {
608 sal_Int32 idx = 1;
609 while( idx < length && (m_aExpr.getStr())[idx] != '?' )
610 // ( isLetterOrDigit( (m_aExpr.getStr())[idx] )
611 // || (m_aExpr.getStr())[idx] == '/'
612 // || (m_aExpr.getStr())[idx] == '.' ))
613 ++idx;
614
615 if( idx != 1 && ! modulePresent )
616 return false;
617 else
618 {
619 m_aId = m_aExpr.copy( 1,idx-1 );
620 m_aExpr = m_aExpr.copy( idx );
621 }
622 }
623
624 // fprintf(stdout,"id %s\n",(rtl::OUStringToOString(m_aId,RTL_TEXTENCODING_UTF8).getStr()));
625 return true;
626 }
627
628
query()629 bool URLParameter::query()
630 {
631 rtl::OUString query_;
632
633 if( ! m_aExpr.getLength() )
634 return true;
635 else if( (m_aExpr.getStr())[0] == sal_Unicode( '?' ) )
636 query_ = m_aExpr.copy( 1 ).trim();
637 else
638 return false;
639
640
641 bool ret = true;
642 sal_Int32 delimIdx,equalIdx;
643 rtl::OUString parameter,value;
644
645 while( query_.getLength() != 0 )
646 {
647 delimIdx = query_.indexOf( sal_Unicode( '&' ) );
648 equalIdx = query_.indexOf( sal_Unicode( '=' ) );
649 parameter = query_.copy( 0,equalIdx ).trim();
650 if( delimIdx == -1 )
651 {
652 value = query_.copy( equalIdx + 1 ).trim();
653 query_ = rtl::OUString();
654 }
655 else
656 {
657 value = query_.copy( equalIdx+1,delimIdx - equalIdx - 1 ).trim();
658 query_ = query_.copy( delimIdx+1 ).trim();
659 }
660
661 if( parameter.compareToAscii( "Language" ) == 0 )
662 m_aLanguage = value;
663 else if( parameter.compareToAscii( "Device" ) == 0 )
664 m_aDevice = value;
665 else if( parameter.compareToAscii( "Program" ) == 0 )
666 m_aProgram = value;
667 else if( parameter.compareToAscii( "Eid" ) == 0 )
668 m_aEid = value;
669 else if( parameter.compareToAscii( "UseDB" ) == 0 )
670 m_bUseDB = ! ( value.compareToAscii("no") == 0 );
671 else if( parameter.compareToAscii( "DbPAR" ) == 0 )
672 m_aDbPar = value;
673 else if( parameter.compareToAscii( "Query" ) == 0 )
674 {
675 if( ! m_aQuery.getLength() )
676 m_aQuery = value;
677 else
678 m_aQuery += ( rtl::OUString::createFromAscii( " " ) + value );
679 }
680 else if( parameter.compareToAscii( "Scope" ) == 0 )
681 m_aScope = value;
682 else if( parameter.compareToAscii( "System" ) == 0 )
683 m_aSystem = value;
684 else if( parameter.compareToAscii( "HelpPrefix" ) == 0 )
685 m_aPrefix = rtl::Uri::decode(
686 value,
687 rtl_UriDecodeWithCharset,
688 RTL_TEXTENCODING_UTF8 );
689 else if( parameter.compareToAscii( "HitCount" ) == 0 )
690 m_nHitCount = value.toInt32();
691 else if( parameter.compareToAscii( "Active" ) == 0 )
692 m_aActive = value;
693 else
694 ret = false;
695 }
696
697 return ret;
698 }
699
700 struct UserData {
701
UserDataUserData702 UserData( InputStreamTransformer* pTransformer,
703 URLParameter* pInitial,
704 Databases* pDatabases )
705 : m_pTransformer( pTransformer ),
706 m_pDatabases( pDatabases ),
707 m_pInitial( pInitial )
708 {
709 }
710
711 InputStreamTransformer* m_pTransformer;
712 Databases* m_pDatabases;
713 URLParameter* m_pInitial;
714 };
715
716 UserData *ugblData = 0;
717
718 extern "C" {
719
720 static int
fileMatch(const char * URI)721 fileMatch(const char * URI) {
722 if ((URI != NULL) && !strncmp(URI, "file:/", 6))
723 return 1;
724 return 0;
725 }
726
727 static int
zipMatch(const char * URI)728 zipMatch(const char * URI) {
729 if ((URI != NULL) && !strncmp(URI, "vnd.sun.star.zip:/", 18))
730 return 1;
731 return 0;
732 }
733
734 static int
helpMatch(const char * URI)735 helpMatch(const char * URI) {
736 if ((URI != NULL) && !strncmp(URI, "vnd.sun.star.help:/", 19))
737 return 1;
738 return 0;
739 }
740
741 static void *
fileOpen(const char * URI)742 fileOpen(const char *URI) {
743 osl::File *pRet = new osl::File(rtl::OUString(URI, strlen(URI), RTL_TEXTENCODING_UTF8));
744 pRet->open(OpenFlag_Read);
745 return pRet;
746 }
747
748 static void *
zipOpen(const char *)749 zipOpen(const char * /*URI*/) {
750 rtl::OUString language,jar,path;
751
752 if( ugblData->m_pInitial->get_eid().getLength() )
753 return (void*)(new Reference< XHierarchicalNameAccess >);
754 else
755 {
756 jar = ugblData->m_pInitial->get_jar();
757 language = ugblData->m_pInitial->get_language();
758 path = ugblData->m_pInitial->get_path();
759 }
760
761 Reference< XHierarchicalNameAccess > xNA =
762 ugblData->m_pDatabases->findJarFileForPath( jar, language, path );
763
764 Reference< XInputStream > xInputStream;
765
766 if( xNA.is() )
767 {
768 try
769 {
770 Any aEntry = xNA->getByHierarchicalName( path );
771 Reference< XActiveDataSink > xSink;
772 if( ( aEntry >>= xSink ) && xSink.is() )
773 xInputStream = xSink->getInputStream();
774 }
775 catch ( NoSuchElementException & )
776 {
777 }
778 }
779
780 if( xInputStream.is() )
781 {
782 return new Reference<XInputStream>(xInputStream);
783 }
784 return 0;
785 }
786
787 static void *
helpOpen(const char * URI)788 helpOpen(const char * URI) {
789 rtl::OUString language,jar,path;
790
791 URLParameter urlpar( rtl::OUString::createFromAscii( URI ),
792 ugblData->m_pDatabases );
793
794 jar = urlpar.get_jar();
795 language = urlpar.get_language();
796 path = urlpar.get_path();
797
798 Reference< XHierarchicalNameAccess > xNA =
799 ugblData->m_pDatabases->findJarFileForPath( jar, language, path );
800
801 Reference< XInputStream > xInputStream;
802
803 if( xNA.is() )
804 {
805 try
806 {
807 Any aEntry = xNA->getByHierarchicalName( path );
808 Reference< XActiveDataSink > xSink;
809 if( ( aEntry >>= xSink ) && xSink.is() )
810 xInputStream = xSink->getInputStream();
811 }
812 catch ( NoSuchElementException & )
813 {
814 }
815 }
816
817 if( xInputStream.is() )
818 return new Reference<XInputStream>(xInputStream);
819 return 0;
820 }
821
822 static int
helpRead(void * context,char * buffer,int len)823 helpRead(void * context, char * buffer, int len) {
824 Reference< XInputStream > *pRef = (Reference< XInputStream >*)context;
825
826 Sequence< sal_Int8 > aSeq;
827 len = (*pRef)->readBytes( aSeq,len);
828 memcpy(buffer, aSeq.getConstArray(), len);
829
830 return len;
831 }
832
833 static int
zipRead(void * context,char * buffer,int len)834 zipRead(void * context, char * buffer, int len) {
835 if( ugblData->m_pInitial->get_eid().getLength() )
836 {
837 ugblData->m_pDatabases->popupDocument( ugblData->m_pInitial,&buffer,&len);
838 return len;
839 }
840 else
841 return helpRead(context, buffer, len);
842 }
843
844 static int
fileRead(void * context,char * buffer,int len)845 fileRead(void * context, char * buffer, int len) {
846 int nRead = 0;
847 osl::File *pFile = (osl::File*)context;
848 if (pFile)
849 {
850 sal_uInt64 uRead = 0;
851 if (osl::FileBase::E_None == pFile->read(buffer, len, uRead))
852 nRead = static_cast<int>(uRead);
853 }
854 return nRead;
855 }
856
857 static int
uriClose(void * context)858 uriClose(void * context) {
859 Reference< XInputStream > *pRef = (Reference< XInputStream >*)context;
860 delete pRef;
861 return 0;
862 }
863
864 static int
fileClose(void * context)865 fileClose(void * context) {
866 osl::File *pFile = (osl::File*)context;
867 if (pFile)
868 {
869 pFile->close();
870 delete pFile;
871 }
872 return 0;
873 }
874
875 } // extern "C"
876
877 /*
878 // For debugging only
879 extern "C" void StructuredXMLErrorFunction(void *userData, xmlErrorPtr error)
880 {
881 (void)userData;
882 (void)error;
883
884 // Reset error handler
885 xmlSetStructuredErrorFunc( NULL, NULL );
886 }
887 */
888
InputStreamTransformer(URLParameter * urlParam,Databases * pDatabases,bool isRoot)889 InputStreamTransformer::InputStreamTransformer( URLParameter* urlParam,
890 Databases* pDatabases,
891 bool isRoot )
892 : len( 0 ),
893 pos( 0 ),
894 buffer( new char[1] ) // Initializing with one element to avoid gcc compiler warning
895 {
896 if( isRoot )
897 {
898 delete[] buffer;
899 pDatabases->cascadingStylesheet( urlParam->get_language(),
900 &buffer,
901 &len );
902 }
903 else if( urlParam->isActive() )
904 {
905 delete[] buffer;
906 pDatabases->setActiveText( urlParam->get_module(),
907 urlParam->get_language(),
908 urlParam->get_id(),
909 &buffer,
910 &len );
911 }
912 else
913 {
914 UserData userData( this,urlParam,pDatabases );
915
916 // Uses the implementation detail, that rtl::OString::getStr returns a zero terminated character-array
917
918 const char* parameter[47];
919 rtl::OString parString[46];
920 int last = 0;
921
922 parString[last++] = "Program";
923 rtl::OString aPureProgramm( urlParam->getByName( "Program" ) );
924 parString[last++] = rtl::OString('\'') + aPureProgramm + rtl::OString('\'');
925 parString[last++] = "Database";
926 parString[last++] = rtl::OString('\'') + urlParam->getByName( "DatabasePar" ) + rtl::OString('\'');
927 parString[last++] = "Id";
928 parString[last++] = rtl::OString('\'') + urlParam->getByName( "Id" ) + rtl::OString('\'');
929 parString[last++] = "Path";
930 rtl::OString aPath( urlParam->getByName( "Path" ) );
931 parString[last++] = rtl::OString('\'') + aPath + rtl::OString('\'');
932
933 rtl::OString aPureLanguage = urlParam->getByName( "Language" );
934 parString[last++] = "Language";
935 parString[last++] = rtl::OString('\'') + aPureLanguage + rtl::OString('\'');
936 parString[last++] = "System";
937 parString[last++] = rtl::OString('\'') + urlParam->getByName( "System" ) + rtl::OString('\'');
938 parString[last++] = "productname";
939 parString[last++] = rtl::OString('\'') + rtl::OString(
940 pDatabases->getProductName().getStr(),
941 pDatabases->getProductName().getLength(),
942 RTL_TEXTENCODING_UTF8 ) + rtl::OString('\'');
943 parString[last++] = "productversion";
944 parString[last++] = rtl::OString('\'') +
945 rtl::OString( pDatabases->getProductVersion().getStr(),
946 pDatabases->getProductVersion().getLength(),
947 RTL_TEXTENCODING_UTF8 ) + rtl::OString('\'');
948
949 parString[last++] = "imgrepos";
950 parString[last++] = rtl::OString('\'') + pDatabases->getImagesZipFileURL() + rtl::OString('\'');
951 parString[last++] = "hp";
952 parString[last++] = rtl::OString('\'') + urlParam->getByName( "HelpPrefix" ) + rtl::OString('\'');
953
954 if( parString[last-1].getLength() )
955 {
956 parString[last++] = "sm";
957 parString[last++] = "'vnd.sun.star.help%3A%2F%2F'";
958 parString[last++] = "qm";
959 parString[last++] = "'%3F'";
960 parString[last++] = "es";
961 parString[last++] = "'%3D'";
962 parString[last++] = "am";
963 parString[last++] = "'%26'";
964 parString[last++] = "cl";
965 parString[last++] = "'%3A'";
966 parString[last++] = "sl";
967 parString[last++] = "'%2F'";
968 parString[last++] = "hm";
969 parString[last++] = "'%23'";
970 parString[last++] = "cs";
971 parString[last++] = "'css'";
972
973 parString[last++] = "vendorname";
974 parString[last++] = rtl::OString("''");
975 parString[last++] = "vendorversion";
976 parString[last++] = rtl::OString("''");
977 parString[last++] = "vendorshort";
978 parString[last++] = rtl::OString("''");
979 }
980
981 // Do we need to add extension path?
982 ::rtl::OUString aExtensionPath;
983 rtl::OUString aJar = urlParam->get_jar();
984
985 bool bAddExtensionPath = false;
986 rtl::OUString aExtensionRegistryPath;
987 sal_Int32 nQuestionMark1 = aJar.indexOf( sal_Unicode('?') );
988 sal_Int32 nQuestionMark2 = aJar.lastIndexOf( sal_Unicode('?') );
989 if( nQuestionMark1 != -1 && nQuestionMark2 != -1 && nQuestionMark1 != nQuestionMark2 )
990 {
991 aExtensionPath = aJar.copy( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 );
992 aExtensionRegistryPath = urlParam->get_ExtensionRegistryPath();
993 bAddExtensionPath = true;
994 }
995 else
996 {
997 // Path not yet specified, search directly
998 Reference< XHierarchicalNameAccess > xNA = pDatabases->findJarFileForPath
999 ( aJar, urlParam->get_language(), urlParam->get_path(), &aExtensionPath, &aExtensionRegistryPath );
1000 if( xNA.is() && aExtensionPath.getLength() )
1001 bAddExtensionPath = true;
1002 }
1003
1004 if( bAddExtensionPath )
1005 {
1006 Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
1007 Reference< XPropertySet > xProps( xFactory, UNO_QUERY );
1008 OSL_ASSERT( xProps.is() );
1009 Reference< XComponentContext > xContext;
1010 if (xProps.is())
1011 {
1012 xProps->getPropertyValue(
1013 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext;
1014 }
1015 if( !xContext.is() )
1016 {
1017 throw RuntimeException(
1018 ::rtl::OUString::createFromAscii( "InputStreamTransformer::InputStreamTransformer(), no XComponentContext" ),
1019 Reference< XInterface >() );
1020 }
1021
1022 rtl::OUString aOUExpandedExtensionPath = Databases::expandURL( aExtensionRegistryPath, xContext );
1023 rtl::OString aExpandedExtensionPath = rtl::OUStringToOString( aOUExpandedExtensionPath, osl_getThreadTextEncoding() );
1024
1025 parString[last++] = "ExtensionPath";
1026 parString[last++] = rtl::OString('\'') + aExpandedExtensionPath + rtl::OString('\'');
1027
1028 // ExtensionId
1029 rtl::OString aPureExtensionId;
1030 sal_Int32 iSlash = aPath.indexOf( '/' );
1031 if( iSlash != -1 )
1032 aPureExtensionId = aPath.copy( 0, iSlash );
1033
1034 parString[last++] = "ExtensionId";
1035 parString[last++] = rtl::OString('\'') + aPureExtensionId + rtl::OString('\'');
1036 }
1037
1038 for( int i = 0; i < last; ++i )
1039 parameter[i] = parString[i].getStr();
1040 parameter[last] = 0;
1041
1042 rtl::OUString xslURL = pDatabases->getInstallPathAsURL();
1043
1044 rtl::OString xslURLascii(
1045 xslURL.getStr(),
1046 xslURL.getLength(),
1047 RTL_TEXTENCODING_UTF8);
1048 xslURLascii += "main_transform.xsl";
1049
1050 ugblData = &userData;
1051
1052 xmlInitParser();
1053 xmlRegisterInputCallbacks(zipMatch, zipOpen, zipRead, uriClose);
1054 xmlRegisterInputCallbacks(helpMatch, helpOpen, helpRead, uriClose);
1055 xmlRegisterInputCallbacks(fileMatch, fileOpen, fileRead, fileClose);
1056 //xmlSetStructuredErrorFunc( NULL, (xmlStructuredErrorFunc)StructuredXMLErrorFunction );
1057
1058 xsltStylesheetPtr cur =
1059 xsltParseStylesheetFile((const xmlChar *)xslURLascii.getStr());
1060
1061 xmlDocPtr doc = xmlParseFile("vnd.sun.star.zip:/");
1062
1063 xmlDocPtr res = xsltApplyStylesheet(cur, doc, parameter);
1064 if (res)
1065 {
1066 xmlChar *doc_txt_ptr=0;
1067 int doc_txt_len;
1068 xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, res, cur);
1069 addToBuffer((const char*)doc_txt_ptr, doc_txt_len);
1070 xmlFree(doc_txt_ptr);
1071 }
1072 xmlPopInputCallbacks(); //filePatch
1073 xmlPopInputCallbacks(); //helpPatch
1074 xmlPopInputCallbacks(); //zipMatch
1075 xmlFreeDoc(res);
1076 xmlFreeDoc(doc);
1077 xsltFreeStylesheet(cur);
1078 }
1079 }
1080
1081
~InputStreamTransformer()1082 InputStreamTransformer::~InputStreamTransformer()
1083 {
1084 delete[] buffer;
1085 }
1086
1087
queryInterface(const Type & rType)1088 Any SAL_CALL InputStreamTransformer::queryInterface( const Type& rType ) throw( RuntimeException )
1089 {
1090 Any aRet = ::cppu::queryInterface( rType,
1091 SAL_STATIC_CAST( XInputStream*,this ),
1092 SAL_STATIC_CAST( XSeekable*,this ) );
1093
1094 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
1095 }
1096
1097
1098
acquire(void)1099 void SAL_CALL InputStreamTransformer::acquire( void ) throw()
1100 {
1101 OWeakObject::acquire();
1102 }
1103
1104
1105
release(void)1106 void SAL_CALL InputStreamTransformer::release( void ) throw()
1107 {
1108 OWeakObject::release();
1109 }
1110
1111
1112
readBytes(Sequence<sal_Int8> & aData,sal_Int32 nBytesToRead)1113 sal_Int32 SAL_CALL InputStreamTransformer::readBytes( Sequence< sal_Int8 >& aData,sal_Int32 nBytesToRead )
1114 throw( NotConnectedException,
1115 BufferSizeExceededException,
1116 IOException,
1117 RuntimeException)
1118 {
1119 osl::MutexGuard aGuard( m_aMutex );
1120
1121 int curr,available_ = len-pos;
1122 if( nBytesToRead <= available_ )
1123 curr = nBytesToRead;
1124 else
1125 curr = available_;
1126
1127 if( 0 <= curr && aData.getLength() < curr )
1128 aData.realloc( curr );
1129
1130 for( int k = 0; k < curr; ++k )
1131 aData[k] = buffer[pos++];
1132
1133 return curr > 0 ? curr : 0;
1134 }
1135
1136
readSomeBytes(Sequence<sal_Int8> & aData,sal_Int32 nMaxBytesToRead)1137 sal_Int32 SAL_CALL InputStreamTransformer::readSomeBytes( Sequence< sal_Int8 >& aData,sal_Int32 nMaxBytesToRead )
1138 throw( NotConnectedException,
1139 BufferSizeExceededException,
1140 IOException,
1141 RuntimeException)
1142 {
1143 return readBytes( aData,nMaxBytesToRead );
1144 }
1145
1146
1147
skipBytes(sal_Int32 nBytesToSkip)1148 void SAL_CALL InputStreamTransformer::skipBytes( sal_Int32 nBytesToSkip ) throw( NotConnectedException,
1149 BufferSizeExceededException,
1150 IOException,
1151 RuntimeException )
1152 {
1153 osl::MutexGuard aGuard( m_aMutex );
1154 while( nBytesToSkip-- ) ++pos;
1155 }
1156
1157
1158
available(void)1159 sal_Int32 SAL_CALL InputStreamTransformer::available( void ) throw( NotConnectedException,
1160 IOException,
1161 RuntimeException )
1162 {
1163 osl::MutexGuard aGuard( m_aMutex );
1164 return len-pos > 0 ? len - pos : 0 ;
1165 }
1166
1167
1168
closeInput(void)1169 void SAL_CALL InputStreamTransformer::closeInput( void ) throw( NotConnectedException,
1170 IOException,
1171 RuntimeException )
1172 {
1173 }
1174
1175
1176
seek(sal_Int64 location)1177 void SAL_CALL InputStreamTransformer::seek( sal_Int64 location ) throw( IllegalArgumentException,
1178 IOException,
1179 RuntimeException )
1180 {
1181 osl::MutexGuard aGuard( m_aMutex );
1182 if( location < 0 )
1183 throw IllegalArgumentException();
1184 else
1185 pos = sal::static_int_cast<sal_Int32>( location );
1186
1187 if( pos > len )
1188 pos = len;
1189 }
1190
1191
1192
getPosition(void)1193 sal_Int64 SAL_CALL InputStreamTransformer::getPosition( void ) throw( IOException,
1194 RuntimeException )
1195 {
1196 osl::MutexGuard aGuard( m_aMutex );
1197 return sal_Int64( pos );
1198 }
1199
1200
1201
getLength(void)1202 sal_Int64 SAL_CALL InputStreamTransformer::getLength( void ) throw( IOException,RuntimeException )
1203 {
1204 osl::MutexGuard aGuard( m_aMutex );
1205
1206 return len;
1207 }
1208
1209
addToBuffer(const char * buffer_,int len_)1210 void InputStreamTransformer::addToBuffer( const char* buffer_,int len_ )
1211 {
1212 osl::MutexGuard aGuard( m_aMutex );
1213
1214 char* tmp = buffer;
1215 buffer = new char[ len+len_ ];
1216 rtl_copyMemory( (void*)(buffer),(void*)(tmp),sal_uInt32( len ) );
1217 rtl_copyMemory( (void*)(buffer+len),(void*)(buffer_),sal_uInt32( len_ ) );
1218 delete[] tmp;
1219 len += len_;
1220 }
1221