xref: /trunk/main/xmlhelp/source/cxxhelp/provider/urlparameter.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 
ascii_isDigit(sal_Unicode ch)68     inline bool ascii_isDigit( sal_Unicode ch )
69     {
70         return ((ch >= 0x0030) && (ch <= 0x0039));
71     }
72 
ascii_isLetter(sal_Unicode ch)73     inline bool ascii_isLetter( sal_Unicode ch )
74     {
75         return ( ( (ch >= 0x0041) && (ch <= 0x005A) ) ||
76                  ( (ch >= 0x0061) && (ch <= 0x007A) ) );
77     }
78 
isLetterOrDigit(sal_Unicode ch)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 
URLParameter(const rtl::OUString & aURL,Databases * pDatabases)96 URLParameter::URLParameter( const rtl::OUString& aURL,
97                             Databases* pDatabases )
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 );
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 
366     virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData,sal_Int32 nMaxBytesToRead );
367 
368     virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip );
369 
370     virtual sal_Int32 SAL_CALL available( void );
371 
372     virtual void SAL_CALL closeInput( void );
373 
374     virtual void SAL_CALL seek( sal_Int64 location );
375 
376     virtual sal_Int64 SAL_CALL getPosition( void );
377 
378     virtual sal_Int64 SAL_CALL getLength( void );
379 
380     void addToBuffer( const char* buffer,int len );
381 
getData() const382     sal_Int8* getData() const { return (sal_Int8*) buffer; }
383 
getLen() const384     sal_Int32 getLen() const { return sal_Int32( len ); }
385 
386 private:
387 
388     osl::Mutex m_aMutex;
389 
390     int len,pos;
391     char *buffer;
392 };
393 
394 
395 
open(const Reference<XMultiServiceFactory> & rxSMgr,const Command & aCommand,sal_Int32 CommandId,const Reference<XCommandEnvironment> & Environment,const Reference<XOutputStream> & xDataSink)396 void URLParameter::open( const Reference< XMultiServiceFactory >& rxSMgr,
397                          const Command& aCommand,
398                          sal_Int32 CommandId,
399                          const Reference< XCommandEnvironment >& Environment,
400                          const Reference< XOutputStream >& xDataSink )
401 {
402     (void)rxSMgr;
403     (void)aCommand;
404     (void)CommandId;
405     (void)Environment;
406 
407     if( ! xDataSink.is() )
408         return;
409 
410     if( isPicture() )
411     {
412         Reference< XInputStream > xStream;
413         Reference< XHierarchicalNameAccess > xNA =
414             m_pDatabases->jarFile( rtl::OUString::createFromAscii( "picture.jar" ),
415                                    get_language() );
416 
417         rtl::OUString path = get_path();
418         if( xNA.is() )
419         {
420             try
421             {
422                 Any aEntry = xNA->getByHierarchicalName( path );
423                 Reference< XActiveDataSink > xSink;
424                 if( ( aEntry >>= xSink ) && xSink.is() )
425                     xStream = xSink->getInputStream();
426             }
427             catch ( NoSuchElementException & )
428             {
429             }
430         }
431         if( xStream.is() )
432         {
433             sal_Int32 ret;
434             Sequence< sal_Int8 > aSeq( 4096 );
435             while( true )
436             {
437                 try
438                 {
439                     ret = xStream->readBytes( aSeq,4096 );
440                     xDataSink->writeBytes( aSeq );
441                     if( ret < 4096 )
442                         break;
443                 }
444                 catch( const Exception& )
445                 {
446                     break;
447                 }
448             }
449         }
450     }
451     else
452     {
453         // a standard document or else an active help text, plug in the new input stream
454         InputStreamTransformer* p = new InputStreamTransformer( this,m_pDatabases,isRoot() );
455         try
456         {
457             xDataSink->writeBytes( Sequence< sal_Int8 >( p->getData(),p->getLen() ) );
458         }
459         catch( const Exception& )
460         {
461         }
462         delete p;
463     }
464     xDataSink->closeOutput();
465 }
466 
467 
468 
open(const Reference<XMultiServiceFactory> & rxSMgr,const Command & aCommand,sal_Int32 CommandId,const Reference<XCommandEnvironment> & Environment,const Reference<XActiveDataSink> & xDataSink)469 void URLParameter::open( const Reference< XMultiServiceFactory >& rxSMgr,
470                          const Command& aCommand,
471                          sal_Int32 CommandId,
472                          const Reference< XCommandEnvironment >& Environment,
473                          const Reference< XActiveDataSink >& xDataSink )
474 {
475     (void)rxSMgr;
476     (void)aCommand;
477     (void)CommandId;
478     (void)Environment;
479 
480     if( isPicture() )
481     {
482         Reference< XInputStream > xStream;
483         Reference< XHierarchicalNameAccess > xNA =
484             m_pDatabases->jarFile( rtl::OUString::createFromAscii( "picture.jar" ),
485                                    get_language() );
486 
487         rtl::OUString path = get_path();
488         if( xNA.is() )
489         {
490             try
491             {
492                 Any aEntry = xNA->getByHierarchicalName( path );
493                 Reference< XActiveDataSink > xSink;
494                 if( ( aEntry >>= xSink ) && xSink.is() )
495                     xStream = xSink->getInputStream();
496             }
497             catch ( NoSuchElementException & )
498             {
499             }
500         }
501 #ifdef WORKAROUND_98119
502         xDataSink->setInputStream( turnToSeekable(xStream) );
503 #else
504         xDataSink->setInputStream( xStream );
505 #endif
506     }
507     else
508         // a standard document or else an active help text, plug in the new input stream
509         xDataSink->setInputStream( new InputStreamTransformer( this,m_pDatabases,isRoot() ) );
510 }
511 
512 
513 // #include <stdio.h>
514 
parse()515 void URLParameter::parse()
516 {
517     // fprintf(stdout,"url send to xmlhelp: %s\n",(rtl::OUStringToOString(m_aURL,RTL_TEXTENCODING_UTF8).getStr()));
518     m_aExpr = m_aURL;
519 
520     sal_Int32 lstIdx = m_aExpr.lastIndexOf( sal_Unicode( '#' ) );
521     if( lstIdx != -1 )
522         m_aExpr = m_aExpr.copy( 0,lstIdx );
523 
524     if( ! scheme() ||
525         ! name( module() ) ||
526         ! query() ||
527         ! m_aLanguage.getLength() ||
528         ! m_aSystem.getLength() )
529         throw com::sun::star::ucb::IllegalIdentifierException();
530 }
531 
532 
scheme()533 bool URLParameter::scheme()
534 {
535     // Correct extension help links as sometimes the
536     // module is missing resulting in a misformed URL
537     if( m_aExpr.compareToAscii( "vnd.sun.star.help:///", 21 ) == 0 )
538     {
539         sal_Int32 nLen = m_aExpr.getLength();
540         rtl::OUString aLastStr = m_aExpr.copy( nLen - 6 );
541         if( aLastStr.compareToAscii( "DbPAR=" ) == 0 )
542         {
543             rtl::OUString aNewExpr = m_aExpr.copy( 0, 20 );
544             rtl::OUString aSharedStr = rtl::OUString::createFromAscii( "shared" );
545             aNewExpr += aSharedStr;
546             aNewExpr += m_aExpr.copy( 20 );
547             aNewExpr += aSharedStr;
548             m_aExpr = aNewExpr;
549         }
550     }
551 
552     for( sal_Int32 nPrefixLen = 20 ; nPrefixLen >= 18 ; --nPrefixLen )
553     {
554         if( m_aExpr.compareToAscii( "vnd.sun.star.help://", nPrefixLen ) == 0 )
555         {
556             m_aExpr = m_aExpr.copy( nPrefixLen );
557             return true;
558         }
559     }
560     return false;
561 }
562 
563 
module()564 bool URLParameter::module()
565 {
566     sal_Int32 idx = 0,length = m_aExpr.getLength();
567 
568     while( idx < length && isLetterOrDigit( (m_aExpr.getStr())[idx] ) )
569         ++idx;
570 
571     if( idx != 0 )
572     {
573         m_aModule = m_aExpr.copy( 0,idx );
574         m_aExpr = m_aExpr.copy( idx );
575         return true;
576     }
577     else
578         return false;
579 }
580 
581 
582 
name(bool modulePresent)583 bool URLParameter::name( bool modulePresent )
584 {
585     // if modulepresent, a name may be present, but must not
586 
587     sal_Int32 length = m_aExpr.getLength();
588 
589     if( length != 0 && (m_aExpr.getStr())[0] == sal_Unicode( '/' ) )
590     {
591         sal_Int32 idx = 1;
592         while( idx < length && (m_aExpr.getStr())[idx] != '?' )
593 //                ( isLetterOrDigit( (m_aExpr.getStr())[idx] )
594 //                  || (m_aExpr.getStr())[idx] == '/'
595 //                  || (m_aExpr.getStr())[idx] == '.' ))
596             ++idx;
597 
598         if( idx != 1 && ! modulePresent )
599             return false;
600         else
601         {
602             m_aId = m_aExpr.copy( 1,idx-1 );
603             m_aExpr = m_aExpr.copy( idx );
604         }
605     }
606 
607 //    fprintf(stdout,"id %s\n",(rtl::OUStringToOString(m_aId,RTL_TEXTENCODING_UTF8).getStr()));
608     return true;
609 }
610 
611 
query()612 bool URLParameter::query()
613 {
614     rtl::OUString query_;
615 
616     if( ! m_aExpr.getLength() )
617         return true;
618     else if( (m_aExpr.getStr())[0] == sal_Unicode( '?' ) )
619         query_ = m_aExpr.copy( 1 ).trim();
620     else
621         return false;
622 
623 
624     bool ret = true;
625     sal_Int32 delimIdx,equalIdx;
626     rtl::OUString parameter,value;
627 
628     while( query_.getLength() != 0 )
629     {
630         delimIdx = query_.indexOf( sal_Unicode( '&' ) );
631         equalIdx = query_.indexOf( sal_Unicode( '=' ) );
632         parameter = query_.copy( 0,equalIdx ).trim();
633         if( delimIdx == -1 )
634         {
635             value = query_.copy( equalIdx + 1 ).trim();
636             query_ = rtl::OUString();
637         }
638         else
639         {
640             value = query_.copy( equalIdx+1,delimIdx - equalIdx - 1 ).trim();
641             query_ = query_.copy( delimIdx+1 ).trim();
642         }
643 
644         if( parameter.compareToAscii( "Language" ) == 0 )
645             m_aLanguage = value;
646         else if( parameter.compareToAscii( "Device" ) == 0 )
647             m_aDevice = value;
648         else if( parameter.compareToAscii( "Program" ) == 0 )
649             m_aProgram = value;
650         else if( parameter.compareToAscii( "Eid" ) == 0 )
651             m_aEid = value;
652         else if( parameter.compareToAscii( "UseDB" ) == 0 )
653             m_bUseDB = ! ( value.compareToAscii("no") == 0 );
654         else if( parameter.compareToAscii( "DbPAR" ) == 0 )
655             m_aDbPar = value;
656         else if( parameter.compareToAscii( "Query" ) == 0 )
657         {
658             if( ! m_aQuery.getLength() )
659                 m_aQuery = value;
660             else
661                 m_aQuery += ( rtl::OUString::createFromAscii( " " ) + value );
662         }
663         else if( parameter.compareToAscii( "Scope" ) == 0 )
664             m_aScope = value;
665         else if( parameter.compareToAscii( "System" ) == 0 )
666             m_aSystem = value;
667         else if( parameter.compareToAscii( "HelpPrefix" ) == 0 )
668             m_aPrefix = rtl::Uri::decode(
669                 value,
670                 rtl_UriDecodeWithCharset,
671                 RTL_TEXTENCODING_UTF8 );
672         else if( parameter.compareToAscii( "HitCount" ) == 0 )
673             m_nHitCount = value.toInt32();
674         else if( parameter.compareToAscii( "Active" ) == 0 )
675             m_aActive = value;
676         else
677             ret = false;
678     }
679 
680     return ret;
681 }
682 
683 struct UserData {
684 
UserDataUserData685     UserData( InputStreamTransformer* pTransformer,
686               URLParameter*           pInitial,
687               Databases*              pDatabases )
688         : m_pTransformer( pTransformer ),
689           m_pDatabases( pDatabases ),
690           m_pInitial( pInitial )
691     {
692     }
693 
694     InputStreamTransformer*             m_pTransformer;
695     Databases*                          m_pDatabases;
696     URLParameter*                       m_pInitial;
697 };
698 
699 UserData *ugblData = 0;
700 
701 extern "C" {
702 
703 static int
fileMatch(const char * URI)704 fileMatch(const char * URI) {
705     if ((URI != NULL) && !strncmp(URI, "file:/", 6))
706         return 1;
707     return 0;
708 }
709 
710 static int
zipMatch(const char * URI)711 zipMatch(const char * URI) {
712     if ((URI != NULL) && !strncmp(URI, "vnd.sun.star.zip:/", 18))
713         return 1;
714     return 0;
715 }
716 
717 static int
helpMatch(const char * URI)718 helpMatch(const char * URI) {
719     if ((URI != NULL) && !strncmp(URI, "vnd.sun.star.help:/", 19))
720         return 1;
721     return 0;
722 }
723 
724 static void *
fileOpen(const char * URI)725 fileOpen(const char *URI) {
726     osl::File *pRet = new osl::File(rtl::OUString(URI, strlen(URI), RTL_TEXTENCODING_UTF8));
727     pRet->open(OpenFlag_Read);
728     return pRet;
729 }
730 
731 static void *
zipOpen(const char *)732 zipOpen(const char * /*URI*/) {
733     rtl::OUString language,jar,path;
734 
735     if( ugblData->m_pInitial->get_eid().getLength() )
736         return (void*)(new Reference< XHierarchicalNameAccess >);
737     else
738     {
739         jar = ugblData->m_pInitial->get_jar();
740         language = ugblData->m_pInitial->get_language();
741         path = ugblData->m_pInitial->get_path();
742     }
743 
744     Reference< XHierarchicalNameAccess > xNA =
745         ugblData->m_pDatabases->findJarFileForPath( jar, language, path );
746 
747     Reference< XInputStream > xInputStream;
748 
749     if( xNA.is() )
750     {
751         try
752         {
753             Any aEntry = xNA->getByHierarchicalName( path );
754             Reference< XActiveDataSink > xSink;
755             if( ( aEntry >>= xSink ) && xSink.is() )
756                 xInputStream = xSink->getInputStream();
757         }
758         catch ( NoSuchElementException & )
759         {
760         }
761     }
762 
763     if( xInputStream.is() )
764     {
765         return new Reference<XInputStream>(xInputStream);
766     }
767     return 0;
768 }
769 
770 static void *
helpOpen(const char * URI)771 helpOpen(const char * URI) {
772     rtl::OUString language,jar,path;
773 
774     URLParameter urlpar( rtl::OUString::createFromAscii( URI ),
775                          ugblData->m_pDatabases );
776 
777     jar = urlpar.get_jar();
778     language = urlpar.get_language();
779     path = urlpar.get_path();
780 
781     Reference< XHierarchicalNameAccess > xNA =
782         ugblData->m_pDatabases->findJarFileForPath( jar, language, path );
783 
784     Reference< XInputStream > xInputStream;
785 
786     if( xNA.is() )
787     {
788         try
789         {
790             Any aEntry = xNA->getByHierarchicalName( path );
791             Reference< XActiveDataSink > xSink;
792             if( ( aEntry >>= xSink ) && xSink.is() )
793                 xInputStream = xSink->getInputStream();
794         }
795         catch ( NoSuchElementException & )
796         {
797         }
798     }
799 
800     if( xInputStream.is() )
801         return new Reference<XInputStream>(xInputStream);
802     return 0;
803 }
804 
805 static int
helpRead(void * context,char * buffer,int len)806 helpRead(void * context, char * buffer, int len) {
807     Reference< XInputStream > *pRef = (Reference< XInputStream >*)context;
808 
809     Sequence< sal_Int8 > aSeq;
810     len = (*pRef)->readBytes( aSeq,len);
811     memcpy(buffer, aSeq.getConstArray(), len);
812 
813     return len;
814 }
815 
816 static int
zipRead(void * context,char * buffer,int len)817 zipRead(void * context, char * buffer, int len) {
818     if( ugblData->m_pInitial->get_eid().getLength() )
819     {
820         ugblData->m_pDatabases->popupDocument( ugblData->m_pInitial,&buffer,&len);
821         return len;
822     }
823     else
824         return helpRead(context, buffer, len);
825 }
826 
827 static int
fileRead(void * context,char * buffer,int len)828 fileRead(void * context, char * buffer, int len) {
829     int nRead = 0;
830     osl::File *pFile = (osl::File*)context;
831     if (pFile)
832     {
833         sal_uInt64 uRead = 0;
834         if (osl::FileBase::E_None == pFile->read(buffer, len, uRead))
835             nRead = static_cast<int>(uRead);
836     }
837     return nRead;
838 }
839 
840 static int
uriClose(void * context)841 uriClose(void * context) {
842     Reference< XInputStream > *pRef = (Reference< XInputStream >*)context;
843     delete pRef;
844     return 0;
845 }
846 
847 static int
fileClose(void * context)848 fileClose(void * context) {
849     osl::File *pFile = (osl::File*)context;
850     if (pFile)
851     {
852         pFile->close();
853         delete pFile;
854     }
855     return 0;
856 }
857 
858 } // extern "C"
859 
860 /*
861 // For debugging only
862 extern "C" void StructuredXMLErrorFunction(void *userData, xmlErrorPtr error)
863 {
864     (void)userData;
865     (void)error;
866 
867     // Reset error handler
868     xmlSetStructuredErrorFunc( NULL, NULL );
869 }
870 */
871 
InputStreamTransformer(URLParameter * urlParam,Databases * pDatabases,bool isRoot)872 InputStreamTransformer::InputStreamTransformer( URLParameter* urlParam,
873                                                 Databases*    pDatabases,
874                                                 bool isRoot )
875     : len( 0 ),
876       pos( 0 ),
877       buffer( new char[1] ) // Initializing with one element to avoid gcc compiler warning
878 {
879     if( isRoot )
880     {
881         delete[] buffer;
882         pDatabases->cascadingStylesheet( urlParam->get_language(),
883                                          &buffer,
884                                          &len );
885     }
886     else if( urlParam->isActive() )
887     {
888         delete[] buffer;
889         pDatabases->setActiveText( urlParam->get_module(),
890                                    urlParam->get_language(),
891                                    urlParam->get_id(),
892                                    &buffer,
893                                    &len );
894     }
895     else
896     {
897         UserData userData( this,urlParam,pDatabases );
898 
899         // Uses the implementation detail, that rtl::OString::getStr returns a zero terminated character-array
900 
901         const char* parameter[47];
902         rtl::OString parString[46];
903         int last = 0;
904 
905         parString[last++] = "Program";
906         rtl::OString aPureProgramm( urlParam->getByName( "Program" ) );
907         parString[last++] = rtl::OString('\'') + aPureProgramm + rtl::OString('\'');
908         parString[last++] = "Database";
909         parString[last++] = rtl::OString('\'') + urlParam->getByName( "DatabasePar" ) + rtl::OString('\'');
910         parString[last++] = "Id";
911         parString[last++] = rtl::OString('\'') + urlParam->getByName( "Id" ) + rtl::OString('\'');
912         parString[last++] = "Path";
913         rtl::OString aPath( urlParam->getByName( "Path" ) );
914         parString[last++] = rtl::OString('\'') + aPath + rtl::OString('\'');
915 
916         rtl::OString aPureLanguage = urlParam->getByName( "Language" );
917         parString[last++] = "Language";
918         parString[last++] = rtl::OString('\'') + aPureLanguage + rtl::OString('\'');
919         parString[last++] = "System";
920         parString[last++] = rtl::OString('\'') + urlParam->getByName( "System" ) + rtl::OString('\'');
921         parString[last++] = "productname";
922         parString[last++] = rtl::OString('\'') + rtl::OString(
923             pDatabases->getProductName().getStr(),
924             pDatabases->getProductName().getLength(),
925             RTL_TEXTENCODING_UTF8 ) + rtl::OString('\'');
926         parString[last++] = "productversion";
927         parString[last++] = rtl::OString('\'') +
928             rtl::OString(  pDatabases->getProductVersion().getStr(),
929                           pDatabases->getProductVersion().getLength(),
930                           RTL_TEXTENCODING_UTF8 ) + rtl::OString('\'');
931 
932         parString[last++] = "imgrepos";
933         parString[last++] = rtl::OString('\'') + pDatabases->getImagesZipFileURL() + rtl::OString('\'');
934         parString[last++] = "hp";
935         parString[last++] = rtl::OString('\'') + urlParam->getByName( "HelpPrefix" ) + rtl::OString('\'');
936 
937         if( parString[last-1].getLength() )
938         {
939             parString[last++] = "sm";
940             parString[last++] = "'vnd.sun.star.help%3A%2F%2F'";
941             parString[last++] = "qm";
942             parString[last++] = "'%3F'";
943             parString[last++] = "es";
944             parString[last++] = "'%3D'";
945             parString[last++] = "am";
946             parString[last++] = "'%26'";
947             parString[last++] = "cl";
948             parString[last++] = "'%3A'";
949             parString[last++] = "sl";
950             parString[last++] = "'%2F'";
951             parString[last++] = "hm";
952             parString[last++] = "'%23'";
953             parString[last++] = "cs";
954             parString[last++] = "'css'";
955 
956             parString[last++] = "vendorname";
957             parString[last++] = rtl::OString("''");
958             parString[last++] = "vendorversion";
959             parString[last++] = rtl::OString("''");
960             parString[last++] = "vendorshort";
961             parString[last++] = rtl::OString("''");
962         }
963 
964         // Do we need to add extension path?
965         ::rtl::OUString aExtensionPath;
966         rtl::OUString aJar = urlParam->get_jar();
967 
968         bool bAddExtensionPath = false;
969         rtl::OUString aExtensionRegistryPath;
970         sal_Int32 nQuestionMark1 = aJar.indexOf( sal_Unicode('?') );
971         sal_Int32 nQuestionMark2 = aJar.lastIndexOf( sal_Unicode('?') );
972         if( nQuestionMark1 != -1 && nQuestionMark2 != -1 && nQuestionMark1 != nQuestionMark2 )
973         {
974             aExtensionPath = aJar.copy( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 );
975             aExtensionRegistryPath = urlParam->get_ExtensionRegistryPath();
976             bAddExtensionPath = true;
977         }
978         else
979         {
980             // Path not yet specified, search directly
981             Reference< XHierarchicalNameAccess > xNA = pDatabases->findJarFileForPath
982                 ( aJar, urlParam->get_language(), urlParam->get_path(), &aExtensionPath, &aExtensionRegistryPath );
983             if( xNA.is() && aExtensionPath.getLength() )
984                 bAddExtensionPath = true;
985         }
986 
987         if( bAddExtensionPath )
988         {
989             Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
990             Reference< XPropertySet > xProps( xFactory, UNO_QUERY );
991             OSL_ASSERT( xProps.is() );
992             Reference< XComponentContext > xContext;
993             if (xProps.is())
994             {
995                 xProps->getPropertyValue(
996                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext;
997             }
998             if( !xContext.is() )
999             {
1000                 throw RuntimeException(
1001                     ::rtl::OUString::createFromAscii( "InputStreamTransformer::InputStreamTransformer(), no XComponentContext" ),
1002                     Reference< XInterface >() );
1003             }
1004 
1005             rtl::OUString aOUExpandedExtensionPath = Databases::expandURL( aExtensionRegistryPath, xContext );
1006             rtl::OString aExpandedExtensionPath = rtl::OUStringToOString( aOUExpandedExtensionPath, osl_getThreadTextEncoding() );
1007 
1008             parString[last++] = "ExtensionPath";
1009             parString[last++] = rtl::OString('\'') + aExpandedExtensionPath + rtl::OString('\'');
1010 
1011             // ExtensionId
1012             rtl::OString aPureExtensionId;
1013             sal_Int32 iSlash = aPath.indexOf( '/' );
1014             if( iSlash != -1 )
1015                 aPureExtensionId = aPath.copy( 0, iSlash );
1016 
1017             parString[last++] = "ExtensionId";
1018             parString[last++] = rtl::OString('\'') + aPureExtensionId + rtl::OString('\'');
1019         }
1020 
1021         for( int i = 0; i < last; ++i )
1022             parameter[i] = parString[i].getStr();
1023         parameter[last] = 0;
1024 
1025         rtl::OUString xslURL = pDatabases->getInstallPathAsURL();
1026 
1027         rtl::OString xslURLascii(
1028             xslURL.getStr(),
1029             xslURL.getLength(),
1030             RTL_TEXTENCODING_UTF8);
1031         xslURLascii += "main_transform.xsl";
1032 
1033         ugblData = &userData;
1034 
1035         xmlInitParser();
1036         xmlRegisterInputCallbacks(zipMatch, zipOpen, zipRead, uriClose);
1037         xmlRegisterInputCallbacks(helpMatch, helpOpen, helpRead, uriClose);
1038         xmlRegisterInputCallbacks(fileMatch, fileOpen, fileRead, fileClose);
1039         //xmlSetStructuredErrorFunc( NULL, (xmlStructuredErrorFunc)StructuredXMLErrorFunction );
1040 
1041         xsltStylesheetPtr cur =
1042             xsltParseStylesheetFile((const xmlChar *)xslURLascii.getStr());
1043 
1044         xmlDocPtr doc = xmlParseFile("vnd.sun.star.zip:/");
1045 
1046         xmlDocPtr res = NULL;
1047         xsltTransformContextPtr transformContext = xsltNewTransformContext(cur, doc);
1048         if (transformContext)
1049         {
1050             xsltSecurityPrefsPtr securityPrefs = xsltNewSecurityPrefs();
1051             if (securityPrefs)
1052             {
1053                 xsltSetSecurityPrefs(securityPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityAllow);
1054                 if (xsltSetCtxtSecurityPrefs(securityPrefs, transformContext) == 0)
1055                 {
1056                     res = xsltApplyStylesheetUser(cur, doc, parameter, NULL, NULL, transformContext);
1057                     if (res)
1058                     {
1059                         xmlChar *doc_txt_ptr=0;
1060                         int doc_txt_len;
1061                         xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, res, cur);
1062                         addToBuffer((const char*)doc_txt_ptr, doc_txt_len);
1063                         xmlFree(doc_txt_ptr);
1064                     }
1065                 }
1066                 xsltFreeSecurityPrefs(securityPrefs);
1067             }
1068             xsltFreeTransformContext(transformContext);
1069         }
1070         xmlPopInputCallbacks(); //filePatch
1071         xmlPopInputCallbacks(); //helpPatch
1072         xmlPopInputCallbacks(); //zipMatch
1073         xmlFreeDoc(res);
1074         xmlFreeDoc(doc);
1075         xsltFreeStylesheet(cur);
1076     }
1077 }
1078 
1079 
~InputStreamTransformer()1080 InputStreamTransformer::~InputStreamTransformer()
1081 {
1082     delete[] buffer;
1083 }
1084 
1085 
queryInterface(const Type & rType)1086 Any SAL_CALL InputStreamTransformer::queryInterface( const Type& rType )
1087 {
1088     Any aRet = ::cppu::queryInterface( rType,
1089                                        SAL_STATIC_CAST( XInputStream*,this ),
1090                                        SAL_STATIC_CAST( XSeekable*,this ) );
1091 
1092     return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
1093 }
1094 
1095 
1096 
acquire(void)1097 void SAL_CALL InputStreamTransformer::acquire( void ) throw()
1098 {
1099     OWeakObject::acquire();
1100 }
1101 
1102 
1103 
release(void)1104 void SAL_CALL InputStreamTransformer::release( void ) throw()
1105 {
1106     OWeakObject::release();
1107 }
1108 
1109 
1110 
readBytes(Sequence<sal_Int8> & aData,sal_Int32 nBytesToRead)1111 sal_Int32 SAL_CALL InputStreamTransformer::readBytes( Sequence< sal_Int8 >& aData,sal_Int32 nBytesToRead )
1112 {
1113     osl::MutexGuard aGuard( m_aMutex );
1114 
1115     int curr,available_ = len-pos;
1116     if( nBytesToRead <= available_ )
1117         curr = nBytesToRead;
1118     else
1119         curr = available_;
1120 
1121     if( 0 <= curr && aData.getLength() < curr )
1122         aData.realloc( curr );
1123 
1124     for( int k = 0; k < curr; ++k )
1125         aData[k] = buffer[pos++];
1126 
1127     return curr > 0 ? curr : 0;
1128 }
1129 
1130 
readSomeBytes(Sequence<sal_Int8> & aData,sal_Int32 nMaxBytesToRead)1131 sal_Int32 SAL_CALL InputStreamTransformer::readSomeBytes( Sequence< sal_Int8 >& aData,sal_Int32 nMaxBytesToRead )
1132 {
1133     return readBytes( aData,nMaxBytesToRead );
1134 }
1135 
1136 
1137 
skipBytes(sal_Int32 nBytesToSkip)1138 void SAL_CALL InputStreamTransformer::skipBytes( sal_Int32 nBytesToSkip )
1139 {
1140     osl::MutexGuard aGuard( m_aMutex );
1141     while( nBytesToSkip-- ) ++pos;
1142 }
1143 
1144 
1145 
available(void)1146 sal_Int32 SAL_CALL InputStreamTransformer::available( void )
1147 {
1148     osl::MutexGuard aGuard( m_aMutex );
1149     return len-pos > 0 ? len - pos : 0 ;
1150 }
1151 
1152 
1153 
closeInput(void)1154 void SAL_CALL InputStreamTransformer::closeInput( void )
1155 {
1156 }
1157 
1158 
1159 
seek(sal_Int64 location)1160 void SAL_CALL InputStreamTransformer::seek( sal_Int64 location )
1161 {
1162     osl::MutexGuard aGuard( m_aMutex );
1163     if( location < 0 )
1164         throw IllegalArgumentException();
1165     else
1166         pos = sal::static_int_cast<sal_Int32>( location );
1167 
1168     if( pos > len )
1169         pos = len;
1170 }
1171 
1172 
1173 
getPosition(void)1174 sal_Int64 SAL_CALL InputStreamTransformer::getPosition( void )
1175 {
1176     osl::MutexGuard aGuard( m_aMutex );
1177     return sal_Int64( pos );
1178 }
1179 
1180 
1181 
getLength(void)1182 sal_Int64 SAL_CALL InputStreamTransformer::getLength( void )
1183 {
1184     osl::MutexGuard aGuard( m_aMutex );
1185 
1186     return len;
1187 }
1188 
1189 
addToBuffer(const char * buffer_,int len_)1190 void InputStreamTransformer::addToBuffer( const char* buffer_,int len_ )
1191 {
1192     osl::MutexGuard aGuard( m_aMutex );
1193 
1194     char* tmp = buffer;
1195     buffer = new char[ len+len_ ];
1196     rtl_copyMemory( (void*)(buffer),(void*)(tmp),sal_uInt32( len ) );
1197     rtl_copyMemory( (void*)(buffer+len),(void*)(buffer_),sal_uInt32( len_ ) );
1198     delete[] tmp;
1199     len += len_;
1200 }
1201