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