xref: /AOO41X/main/xmlhelp/source/cxxhelp/provider/urlparameter.cxx (revision 70e197d992a972622ba2d0ef1e21a10194579c24)
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