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