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