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