1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_xmlhelp.hxx"
26 
27 #define WORKAROUND_98119
28 
29 #ifdef WORKAROUND_98119
30 #include "bufferedinputstream.hxx"
31 #endif
32 
33 #include <string.h>
34 #ifndef _VOS_DIAGNOSE_HXX_
35 #include <vos/diagnose.hxx>
36 #endif
37 #include <osl/thread.h>
38 #include <rtl/memory.h>
39 #include <osl/file.hxx>
40 #include <cppuhelper/weak.hxx>
41 #include <cppuhelper/queryinterface.hxx>
42 #include <comphelper/processfactory.hxx>
43 #include <rtl/uri.hxx>
44 #include <rtl/ustrbuf.hxx>
45 #include <libxslt/xslt.h>
46 #include <libxslt/transform.h>
47 #include <libxslt/xsltutils.h>
48 #include "db.hxx"
49 #include <com/sun/star/io/XActiveDataSink.hpp>
50 #include <com/sun/star/io/XInputStream.hpp>
51 #include <com/sun/star/io/XSeekable.hpp>
52 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
53 #include <com/sun/star/ucb/OpenMode.hpp>
54 #include <com/sun/star/ucb/XCommandProcessor.hpp>
55 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
56 #include <com/sun/star/ucb/XContentIdentifier.hpp>
57 #include <com/sun/star/ucb/XContentProvider.hpp>
58 #include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
59 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
60 #include <com/sun/star/beans/XPropertySet.hpp>
61 
62 #include "urlparameter.hxx"
63 #include "databases.hxx"
64 
65 namespace chelp {
66 
67 	inline bool ascii_isDigit( sal_Unicode ch )
68 	{
69 		return ((ch >= 0x0030) && (ch <= 0x0039));
70 	}
71 
72 	inline bool ascii_isLetter( sal_Unicode ch )
73 	{
74 		return ( ( (ch >= 0x0041) && (ch <= 0x005A) ) ||
75 				 ( (ch >= 0x0061) && (ch <= 0x007A) ) );
76 	}
77 
78 	inline bool isLetterOrDigit( sal_Unicode ch )
79 	{
80 		return ascii_isLetter( ch ) || ascii_isDigit( ch );
81 	}
82 
83 }
84 
85 using namespace cppu;
86 using namespace com::sun::star::io;
87 using namespace com::sun::star::uno;
88 using namespace com::sun::star::lang;
89 using namespace com::sun::star::ucb;
90 using namespace com::sun::star::beans;
91 using namespace com::sun::star::container;
92 using namespace berkeleydbproxy;
93 using namespace chelp;
94 
95 
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 
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 
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 
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 
163 rtl::OUString URLParameter::get_tag()
164 {
165 	if( isFile() )
166 		return get_the_tag();
167 	else
168 		return m_aTag;
169 }
170 
171 
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 
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 
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 
214 void URLParameter::init( bool bDefaultLanguageIsInitialized )
215 {
216 	(void)bDefaultLanguageIsInitialized;
217 
218 	m_bBerkeleyRead = false;
219 	m_bStart = false;
220     m_bUseDB = true;
221 	m_nHitCount = 100;                // The default maximum hitcount
222 }
223 
224 
225 rtl::OUString URLParameter::get_the_tag()
226 {
227     if(m_bUseDB) {
228         if( ! m_bBerkeleyRead )
229             readBerkeley();
230 
231         m_bBerkeleyRead = true;
232 
233         return m_aTag;
234     }
235     else
236         return rtl::OUString();
237 }
238 
239 
240 
241 rtl::OUString URLParameter::get_the_path()
242 {
243     if(m_bUseDB) {
244         if( ! m_bBerkeleyRead )
245             readBerkeley();
246         m_bBerkeleyRead = true;
247 
248         return m_aPath;
249     }
250     else
251         return get_id();
252 }
253 
254 
255 
256 rtl::OUString URLParameter::get_the_title()
257 {
258     if(m_bUseDB) {
259         if( ! m_bBerkeleyRead )
260             readBerkeley();
261         m_bBerkeleyRead = true;
262 
263         return m_aTitle;
264     }
265     else
266         return rtl::OUString();
267 }
268 
269 
270 rtl::OUString URLParameter::get_the_jar()
271 {
272     if(m_bUseDB) {
273         if( ! m_bBerkeleyRead )
274             readBerkeley();
275         m_bBerkeleyRead = true;
276 
277         return m_aJar;
278     }
279     else
280         return get_module() + rtl::OUString::createFromAscii(".jar");
281 }
282 
283 
284 
285 
286 void URLParameter::readBerkeley()
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 	Dbt data;
303 	DBData aDBData;
304 	rtl::OUString aExtensionPath;
305     rtl::OUString aExtensionRegistryPath;
306 	while( true )
307 	{
308 		Db* db = aDbIt.nextDb( &aExtensionPath, &aExtensionRegistryPath );
309 		if( !db )
310 			break;
311 
312 		rtl::OString keyStr( m_aId.getStr(),m_aId.getLength(),RTL_TEXTENCODING_UTF8 );
313 
314 		DBHelp* pDBHelp = db->getDBHelp();
315 		if( pDBHelp != NULL )
316 		{
317 			bSuccess = pDBHelp->getValueForKey( keyStr, aDBData );
318 			if( bSuccess )
319 			{
320 				nSize = aDBData.getSize();
321 				pData = aDBData.getData();
322 				break;
323 			}
324 		}
325 		else
326 		{
327 			Dbt key( static_cast< void* >( const_cast< sal_Char* >( keyStr.getStr() ) ),
328 					 keyStr.getLength() );
329 			int err = db->get( 0,&key,&data,0 );
330 			if( err == 0 )
331 			{
332 				bSuccess = true;
333 				nSize = data.get_size();
334 				pData = static_cast<sal_Char*>( data.get_data() );
335 				break;
336 			}
337 		}
338 	}
339 
340 	if( bSuccess )
341 	{
342 		DbtToStringConverter converter( pData, nSize );
343 		m_aTitle = converter.getTitle();
344 		m_pDatabases->replaceName( m_aTitle );
345 		m_aPath  = converter.getFile();
346 		m_aJar   = converter.getDatabase();
347 		if( aExtensionPath.getLength() > 0 )
348 		{
349 			rtl::OUStringBuffer aExtendedJarStrBuf;
350 			aExtendedJarStrBuf.append( aQuestionMark );
351 			aExtendedJarStrBuf.append( aExtensionPath );
352 			aExtendedJarStrBuf.append( aQuestionMark );
353 			aExtendedJarStrBuf.append( m_aJar );
354 			m_aJar = aExtendedJarStrBuf.makeStringAndClear();
355             m_aExtensionRegistryPath = aExtensionRegistryPath;
356 		}
357 		m_aTag   = converter.getHash();
358 	}
359 }
360 
361 
362 
363 // Class encapsulating the transformation of the XInputStream to XHTML
364 
365 
366 class InputStreamTransformer
367 	: public OWeakObject,
368 	  public XInputStream,
369 	  public XSeekable
370 {
371 public:
372 
373 	InputStreamTransformer( URLParameter* urlParam,
374 							Databases*    pDatatabases,
375 							bool isRoot = false );
376 
377 	~InputStreamTransformer();
378 
379 	virtual Any SAL_CALL queryInterface( const Type& rType ) throw( RuntimeException );
380 	virtual void SAL_CALL acquire( void ) throw();
381 	virtual void SAL_CALL release( void ) throw();
382 
383 	virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData,sal_Int32 nBytesToRead )
384 		throw( NotConnectedException,
385 			   BufferSizeExceededException,
386 			   IOException,
387 			   RuntimeException);
388 
389 	virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData,sal_Int32 nMaxBytesToRead )
390 		throw( NotConnectedException,
391 			   BufferSizeExceededException,
392 			   IOException,
393 			   RuntimeException);
394 
395 	virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) throw( NotConnectedException,
396 																	 BufferSizeExceededException,
397 																	 IOException,
398 																	 RuntimeException );
399 
400 	virtual sal_Int32 SAL_CALL available( void ) throw( NotConnectedException,
401 														IOException,
402 														RuntimeException );
403 
404 	virtual void SAL_CALL closeInput( void ) throw( NotConnectedException,
405 													IOException,
406 													RuntimeException );
407 
408 	virtual void SAL_CALL seek( sal_Int64 location ) throw( IllegalArgumentException,
409 															IOException,
410 															RuntimeException );
411 
412 	virtual sal_Int64 SAL_CALL getPosition( void ) throw( IOException,RuntimeException );
413 
414 	virtual sal_Int64 SAL_CALL getLength( void ) throw( IOException,RuntimeException );
415 
416 	void addToBuffer( const char* buffer,int len );
417 
418 	sal_Int8* getData() const { return (sal_Int8*) buffer; }
419 
420     sal_Int32 getLen() const { return sal_Int32( len ); }
421 
422 private:
423 
424 	osl::Mutex m_aMutex;
425 
426 	int len,pos;
427 	char *buffer;
428 };
429 
430 
431 
432 void URLParameter::open( const Reference< XMultiServiceFactory >& rxSMgr,
433 						 const Command& aCommand,
434 						 sal_Int32 CommandId,
435 						 const Reference< XCommandEnvironment >& Environment,
436 						 const Reference< XOutputStream >& xDataSink )
437 {
438 	(void)rxSMgr;
439 	(void)aCommand;
440 	(void)CommandId;
441 	(void)Environment;
442 
443     if( ! xDataSink.is() )
444         return;
445 
446 	if( isPicture() )
447 	{
448 		Reference< XInputStream > xStream;
449 		Reference< XHierarchicalNameAccess > xNA =
450 			m_pDatabases->jarFile( rtl::OUString::createFromAscii( "picture.jar" ),
451 								   get_language() );
452 
453 		rtl::OUString path = get_path();
454 		if( xNA.is() )
455 		{
456 			try
457 			{
458 				Any aEntry = xNA->getByHierarchicalName( path );
459 				Reference< XActiveDataSink > xSink;
460 				if( ( aEntry >>= xSink ) && xSink.is() )
461 					xStream = xSink->getInputStream();
462 			}
463 			catch ( NoSuchElementException & )
464 			{
465 			}
466 		}
467         if( xStream.is() )
468         {
469             sal_Int32 ret;
470             Sequence< sal_Int8 > aSeq( 4096 );
471             while( true )
472             {
473                 try
474                 {
475                     ret = xStream->readBytes( aSeq,4096 );
476                     xDataSink->writeBytes( aSeq );
477                     if( ret < 4096 )
478                         break;
479                 }
480                 catch( const Exception& )
481                 {
482                     break;
483                 }
484             }
485         }
486 	}
487 	else
488     {
489 		// a standard document or else an active help text, plug in the new input stream
490 		InputStreamTransformer* p = new InputStreamTransformer( this,m_pDatabases,isRoot() );
491         try
492         {
493             xDataSink->writeBytes( Sequence< sal_Int8 >( p->getData(),p->getLen() ) );
494         }
495         catch( const Exception& )
496         {
497         }
498         delete p;
499     }
500     xDataSink->closeOutput();
501 }
502 
503 
504 
505 void URLParameter::open( const Reference< XMultiServiceFactory >& rxSMgr,
506 						 const Command& aCommand,
507 						 sal_Int32 CommandId,
508 						 const Reference< XCommandEnvironment >& Environment,
509 						 const Reference< XActiveDataSink >& xDataSink )
510 {
511 	(void)rxSMgr;
512 	(void)aCommand;
513 	(void)CommandId;
514 	(void)Environment;
515 
516 	if( isPicture() )
517 	{
518 		Reference< XInputStream > xStream;
519 		Reference< XHierarchicalNameAccess > xNA =
520 			m_pDatabases->jarFile( rtl::OUString::createFromAscii( "picture.jar" ),
521 								   get_language() );
522 
523 		rtl::OUString path = get_path();
524 		if( xNA.is() )
525 		{
526 			try
527 			{
528 				Any aEntry = xNA->getByHierarchicalName( path );
529 				Reference< XActiveDataSink > xSink;
530 				if( ( aEntry >>= xSink ) && xSink.is() )
531 					xStream = xSink->getInputStream();
532 			}
533 			catch ( NoSuchElementException & )
534 			{
535 			}
536 		}
537 #ifdef WORKAROUND_98119
538 		xDataSink->setInputStream( turnToSeekable(xStream) );
539 #else
540 		xDataSink->setInputStream( xStream );
541 #endif
542 	}
543 	else
544 		// a standard document or else an active help text, plug in the new input stream
545 		xDataSink->setInputStream( new InputStreamTransformer( this,m_pDatabases,isRoot() ) );
546 }
547 
548 
549 // #include <stdio.h>
550 
551 void URLParameter::parse() throw( com::sun::star::ucb::IllegalIdentifierException )
552 {
553     // fprintf(stdout,"url send to xmlhelp: %s\n",(rtl::OUStringToOString(m_aURL,RTL_TEXTENCODING_UTF8).getStr()));
554 	m_aExpr = m_aURL;
555 
556 	sal_Int32 lstIdx = m_aExpr.lastIndexOf( sal_Unicode( '#' ) );
557 	if( lstIdx != -1 )
558 		m_aExpr = m_aExpr.copy( 0,lstIdx );
559 
560 	if( ! scheme() ||
561         ! name( module() ) ||
562         ! query() ||
563         ! m_aLanguage.getLength() ||
564         ! m_aSystem.getLength() )
565 		throw com::sun::star::ucb::IllegalIdentifierException();
566 }
567 
568 
569 bool URLParameter::scheme()
570 {
571 	// Correct extension help links as sometimes the
572 	// module is missing resulting in a misformed URL
573 	if( m_aExpr.compareToAscii( "vnd.sun.star.help:///", 21 ) == 0 )
574 	{
575 		sal_Int32 nLen = m_aExpr.getLength();
576 		rtl::OUString aLastStr = m_aExpr.copy( nLen - 6 );
577 		if( aLastStr.compareToAscii( "DbPAR=" ) == 0 )
578 		{
579 			rtl::OUString aNewExpr = m_aExpr.copy( 0, 20 );
580 			rtl::OUString aSharedStr = rtl::OUString::createFromAscii( "shared" );
581 			aNewExpr += aSharedStr;
582 			aNewExpr += m_aExpr.copy( 20 );
583 			aNewExpr += aSharedStr;
584 			m_aExpr = aNewExpr;
585 		}
586 	}
587 
588 	for( sal_Int32 nPrefixLen = 20 ; nPrefixLen >= 18 ; --nPrefixLen )
589 	{
590 		if( m_aExpr.compareToAscii( "vnd.sun.star.help://", nPrefixLen ) == 0 )
591 		{
592 			m_aExpr = m_aExpr.copy( nPrefixLen );
593 			return true;
594 		}
595 	}
596 	return false;
597 }
598 
599 
600 bool URLParameter::module()
601 {
602 	sal_Int32 idx = 0,length = m_aExpr.getLength();
603 
604 	while( idx < length && isLetterOrDigit( (m_aExpr.getStr())[idx] ) )
605 		++idx;
606 
607 	if( idx != 0 )
608 	{
609 		m_aModule = m_aExpr.copy( 0,idx );
610 		m_aExpr = m_aExpr.copy( idx );
611 		return true;
612 	}
613 	else
614 		return false;
615 }
616 
617 
618 
619 bool URLParameter::name( bool modulePresent )
620 {
621 	// if modulepresent, a name may be present, but must not
622 
623 	sal_Int32 length = m_aExpr.getLength();
624 
625 	if( length != 0 && (m_aExpr.getStr())[0] == sal_Unicode( '/' ) )
626 	{
627 		sal_Int32 idx = 1;
628 		while( idx < length && (m_aExpr.getStr())[idx] != '?' )
629 //                ( isLetterOrDigit( (m_aExpr.getStr())[idx] )
630 //                  || (m_aExpr.getStr())[idx] == '/'
631 //                  || (m_aExpr.getStr())[idx] == '.' ))
632 			++idx;
633 
634 		if( idx != 1 && ! modulePresent )
635 			return false;
636 		else
637 		{
638 			m_aId = m_aExpr.copy( 1,idx-1 );
639 			m_aExpr = m_aExpr.copy( idx );
640 		}
641 	}
642 
643 //    fprintf(stdout,"id %s\n",(rtl::OUStringToOString(m_aId,RTL_TEXTENCODING_UTF8).getStr()));
644 	return true;
645 }
646 
647 
648 bool URLParameter::query()
649 {
650 	rtl::OUString query_;
651 
652 	if( ! m_aExpr.getLength() )
653 		return true;
654 	else if( (m_aExpr.getStr())[0] == sal_Unicode( '?' ) )
655 		query_ = m_aExpr.copy( 1 ).trim();
656 	else
657 		return false;
658 
659 
660 	bool ret = true;
661 	sal_Int32 delimIdx,equalIdx;
662 	rtl::OUString parameter,value;
663 
664 	while( query_.getLength() != 0 )
665 	{
666 		delimIdx = query_.indexOf( sal_Unicode( '&' ) );
667 		equalIdx = query_.indexOf( sal_Unicode( '=' ) );
668 		parameter = query_.copy( 0,equalIdx ).trim();
669 		if( delimIdx == -1 )
670 		{
671 			value = query_.copy( equalIdx + 1 ).trim();
672 			query_ = rtl::OUString();
673 		}
674 		else
675 		{
676 			value = query_.copy( equalIdx+1,delimIdx - equalIdx - 1 ).trim();
677 			query_ = query_.copy( delimIdx+1 ).trim();
678 		}
679 
680 		if( parameter.compareToAscii( "Language" ) == 0 )
681 			m_aLanguage = value;
682 		else if( parameter.compareToAscii( "Device" ) == 0 )
683 			m_aDevice = value;
684 		else if( parameter.compareToAscii( "Program" ) == 0 )
685 			m_aProgram = value;
686 		else if( parameter.compareToAscii( "Eid" ) == 0 )
687 			m_aEid = value;
688 		else if( parameter.compareToAscii( "UseDB" ) == 0 )
689             m_bUseDB = ! ( value.compareToAscii("no") == 0 );
690         else if( parameter.compareToAscii( "DbPAR" ) == 0 )
691             m_aDbPar = value;
692 		else if( parameter.compareToAscii( "Query" ) == 0 )
693 		{
694 			if( ! m_aQuery.getLength() )
695 				m_aQuery = value;
696 			else
697 				m_aQuery += ( rtl::OUString::createFromAscii( " " ) + value );
698 		}
699 		else if( parameter.compareToAscii( "Scope" ) == 0 )
700 			m_aScope = value;
701 		else if( parameter.compareToAscii( "System" ) == 0 )
702 			m_aSystem = value;
703 		else if( parameter.compareToAscii( "HelpPrefix" ) == 0 )
704 			m_aPrefix = rtl::Uri::decode(
705                 value,
706                 rtl_UriDecodeWithCharset,
707                 RTL_TEXTENCODING_UTF8 );
708 		else if( parameter.compareToAscii( "HitCount" ) == 0 )
709 			m_nHitCount = value.toInt32();
710 		else if( parameter.compareToAscii( "Active" ) == 0 )
711 			m_aActive = value;
712 		else
713 			ret = false;
714 	}
715 
716 	return ret;
717 }
718 
719 struct UserData {
720 
721 	UserData( InputStreamTransformer* pTransformer,
722 			  URLParameter*           pInitial,
723 			  Databases*              pDatabases )
724 		: m_pTransformer( pTransformer ),
725           m_pDatabases( pDatabases ),
726 		  m_pInitial( pInitial )
727 	{
728 	}
729 
730 	InputStreamTransformer*             m_pTransformer;
731 	Databases*                          m_pDatabases;
732 	URLParameter*                       m_pInitial;
733 };
734 
735 UserData *ugblData = 0;
736 
737 extern "C" {
738 
739 static int
740 fileMatch(const char * URI) {
741 	if ((URI != NULL) && !strncmp(URI, "file:/", 6))
742         return 1;
743     return 0;
744 }
745 
746 static int
747 zipMatch(const char * URI) {
748 	if ((URI != NULL) && !strncmp(URI, "vnd.sun.star.zip:/", 18))
749         return 1;
750     return 0;
751 }
752 
753 static int
754 helpMatch(const char * URI) {
755 	if ((URI != NULL) && !strncmp(URI, "vnd.sun.star.help:/", 19))
756         return 1;
757     return 0;
758 }
759 
760 static void *
761 fileOpen(const char *URI) {
762 	osl::File *pRet = new osl::File(rtl::OUString(URI, strlen(URI), RTL_TEXTENCODING_UTF8));
763 	pRet->open(OpenFlag_Read);
764 	return pRet;
765 }
766 
767 static void *
768 zipOpen(const char * /*URI*/) {
769 	rtl::OUString language,jar,path;
770 
771 	if( ugblData->m_pInitial->get_eid().getLength() )
772 		return (void*)(new Reference< XHierarchicalNameAccess >);
773 	else
774 	{
775 		jar = ugblData->m_pInitial->get_jar();
776 		language = ugblData->m_pInitial->get_language();
777 		path = ugblData->m_pInitial->get_path();
778 	}
779 
780 	Reference< XHierarchicalNameAccess > xNA =
781 		ugblData->m_pDatabases->findJarFileForPath( jar, language, path );
782 
783     Reference< XInputStream > xInputStream;
784 
785 	if( xNA.is() )
786 	{
787 		try
788 		{
789 			Any aEntry = xNA->getByHierarchicalName( path );
790 			Reference< XActiveDataSink > xSink;
791 			if( ( aEntry >>= xSink ) && xSink.is() )
792 				xInputStream = xSink->getInputStream();
793 		}
794 		catch ( NoSuchElementException & )
795 		{
796 		}
797 	}
798 
799 	if( xInputStream.is() )
800 	{
801 		return new Reference<XInputStream>(xInputStream);
802 	}
803 	return 0;
804 }
805 
806 static void *
807 helpOpen(const char * URI) {
808 	rtl::OUString language,jar,path;
809 
810 	URLParameter urlpar( rtl::OUString::createFromAscii( URI ),
811 						 ugblData->m_pDatabases );
812 
813 	jar = urlpar.get_jar();
814 	language = urlpar.get_language();
815 	path = urlpar.get_path();
816 
817 	Reference< XHierarchicalNameAccess > xNA =
818 		ugblData->m_pDatabases->findJarFileForPath( jar, language, path );
819 
820     Reference< XInputStream > xInputStream;
821 
822 	if( xNA.is() )
823 	{
824 		try
825 		{
826 			Any aEntry = xNA->getByHierarchicalName( path );
827 			Reference< XActiveDataSink > xSink;
828 			if( ( aEntry >>= xSink ) && xSink.is() )
829 				xInputStream = xSink->getInputStream();
830 		}
831 		catch ( NoSuchElementException & )
832 		{
833 		}
834 	}
835 
836 	if( xInputStream.is() )
837 		return new Reference<XInputStream>(xInputStream);
838 	return 0;
839 }
840 
841 static int
842 helpRead(void * context, char * buffer, int len) {
843 	Reference< XInputStream > *pRef = (Reference< XInputStream >*)context;
844 
845 	Sequence< sal_Int8 > aSeq;
846 	len = (*pRef)->readBytes( aSeq,len);
847 	memcpy(buffer, aSeq.getConstArray(), len);
848 
849 	return len;
850 }
851 
852 static int
853 zipRead(void * context, char * buffer, int len) {
854 	if( ugblData->m_pInitial->get_eid().getLength() )
855 	{
856 		ugblData->m_pDatabases->popupDocument( ugblData->m_pInitial,&buffer,&len);
857 		return len;
858 	}
859 	else
860 		return helpRead(context, buffer, len);
861 }
862 
863 static int
864 fileRead(void * context, char * buffer, int len) {
865 	int nRead = 0;
866 	osl::File *pFile = (osl::File*)context;
867 	if (pFile)
868 	{
869 		sal_uInt64 uRead = 0;
870 		if (osl::FileBase::E_None == pFile->read(buffer, len, uRead))
871 			nRead = static_cast<int>(uRead);
872 	}
873 	return nRead;
874 }
875 
876 static int
877 uriClose(void * context) {
878 	Reference< XInputStream > *pRef = (Reference< XInputStream >*)context;
879 	delete pRef;
880     return 0;
881 }
882 
883 static int
884 fileClose(void * context) {
885 	osl::File *pFile = (osl::File*)context;
886 	if (pFile)
887 	{
888 		pFile->close();
889 		delete pFile;
890 	}
891 	return 0;
892 }
893 
894 } // extern "C"
895 
896 /*
897 // For debugging only
898 extern "C" void StructuredXMLErrorFunction(void *userData, xmlErrorPtr error)
899 {
900 	(void)userData;
901 	(void)error;
902 
903 	// Reset error handler
904 	xmlSetStructuredErrorFunc( NULL, NULL );
905 }
906 */
907 
908 InputStreamTransformer::InputStreamTransformer( URLParameter* urlParam,
909 												Databases*    pDatabases,
910 												bool isRoot )
911 	: len( 0 ),
912 	  pos( 0 ),
913 	  buffer( new char[1] ) // Initializing with one element to avoid gcc compiler warning
914 {
915 	if( isRoot )
916 	{
917 		delete[] buffer;
918 		pDatabases->cascadingStylesheet( urlParam->get_language(),
919 										 &buffer,
920 										 &len );
921 	}
922 	else if( urlParam->isActive() )
923 	{
924 		delete[] buffer;
925 		pDatabases->setActiveText( urlParam->get_module(),
926 								   urlParam->get_language(),
927 								   urlParam->get_id(),
928 								   &buffer,
929 								   &len );
930 	}
931 	else
932 	{
933 		UserData userData( this,urlParam,pDatabases );
934 
935 		// Uses the implementation detail, that rtl::OString::getStr returns a zero terminated character-array
936 
937 		const char* parameter[47];
938 		rtl::OString parString[46];
939 		int last = 0;
940 
941 		parString[last++] = "Program";
942 		rtl::OString aPureProgramm( urlParam->getByName( "Program" ) );
943 		parString[last++] = rtl::OString('\'') + aPureProgramm + rtl::OString('\'');
944 		parString[last++] = "Database";
945 		parString[last++] = rtl::OString('\'') + urlParam->getByName( "DatabasePar" ) + rtl::OString('\'');
946 		parString[last++] = "Id";
947 		parString[last++] = rtl::OString('\'') + urlParam->getByName( "Id" ) + rtl::OString('\'');
948 		parString[last++] = "Path";
949 		rtl::OString aPath( urlParam->getByName( "Path" ) );
950 		parString[last++] = rtl::OString('\'') + aPath + rtl::OString('\'');
951 
952 		rtl::OString aPureLanguage = urlParam->getByName( "Language" );
953 		parString[last++] = "Language";
954 		parString[last++] = rtl::OString('\'') + aPureLanguage + rtl::OString('\'');
955 		parString[last++] = "System";
956 		parString[last++] = rtl::OString('\'') + urlParam->getByName( "System" ) + rtl::OString('\'');
957 		parString[last++] = "productname";
958 		parString[last++] = rtl::OString('\'') + rtl::OString(
959             pDatabases->getProductName().getStr(),
960             pDatabases->getProductName().getLength(),
961             RTL_TEXTENCODING_UTF8 ) + rtl::OString('\'');
962 		parString[last++] = "productversion";
963 		parString[last++] = rtl::OString('\'') +
964             rtl::OString(  pDatabases->getProductVersion().getStr(),
965                           pDatabases->getProductVersion().getLength(),
966                           RTL_TEXTENCODING_UTF8 ) + rtl::OString('\'');
967 
968         parString[last++] = "imgrepos";
969         parString[last++] = rtl::OString('\'') + pDatabases->getImagesZipFileURL() + rtl::OString('\'');
970         parString[last++] = "hp";
971         parString[last++] = rtl::OString('\'') + urlParam->getByName( "HelpPrefix" ) + rtl::OString('\'');
972 
973         if( parString[last-1].getLength() )
974         {
975             parString[last++] = "sm";
976             parString[last++] = "'vnd.sun.star.help%3A%2F%2F'";
977             parString[last++] = "qm";
978             parString[last++] = "'%3F'";
979             parString[last++] = "es";
980             parString[last++] = "'%3D'";
981             parString[last++] = "am";
982             parString[last++] = "'%26'";
983             parString[last++] = "cl";
984             parString[last++] = "'%3A'";
985             parString[last++] = "sl";
986             parString[last++] = "'%2F'";
987             parString[last++] = "hm";
988             parString[last++] = "'%23'";
989             parString[last++] = "cs";
990             parString[last++] = "'css'";
991 
992             parString[last++] = "vendorname";
993             parString[last++] = rtl::OString("''");
994             parString[last++] = "vendorversion";
995             parString[last++] = rtl::OString("''");
996             parString[last++] = "vendorshort";
997             parString[last++] = rtl::OString("''");
998         }
999 
1000 		// Do we need to add extension path?
1001 		::rtl::OUString aExtensionPath;
1002 		rtl::OUString aJar = urlParam->get_jar();
1003 
1004 		bool bAddExtensionPath = false;
1005         rtl::OUString aExtensionRegistryPath;
1006         sal_Int32 nQuestionMark1 = aJar.indexOf( sal_Unicode('?') );
1007         sal_Int32 nQuestionMark2 = aJar.lastIndexOf( sal_Unicode('?') );
1008 		if( nQuestionMark1 != -1 && nQuestionMark2 != -1 && nQuestionMark1 != nQuestionMark2 )
1009 		{
1010 			aExtensionPath = aJar.copy( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 );
1011             aExtensionRegistryPath = urlParam->get_ExtensionRegistryPath();
1012 			bAddExtensionPath = true;
1013 		}
1014 		else
1015 		{
1016 			// Path not yet specified, search directly
1017 			Reference< XHierarchicalNameAccess > xNA = pDatabases->findJarFileForPath
1018 				( aJar, urlParam->get_language(), urlParam->get_path(), &aExtensionPath, &aExtensionRegistryPath );
1019 			if( xNA.is() && aExtensionPath.getLength() )
1020 				bAddExtensionPath = true;
1021 		}
1022 
1023 		if( bAddExtensionPath )
1024 		{
1025 			Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
1026 			Reference< XPropertySet > xProps( xFactory, UNO_QUERY );
1027 			OSL_ASSERT( xProps.is() );
1028 			Reference< XComponentContext > xContext;
1029 			if (xProps.is())
1030 			{
1031 				xProps->getPropertyValue(
1032 					::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext;
1033 			}
1034 			if( !xContext.is() )
1035 			{
1036 				throw RuntimeException(
1037 					::rtl::OUString::createFromAscii( "InputStreamTransformer::InputStreamTransformer(), no XComponentContext" ),
1038 					Reference< XInterface >() );
1039 			}
1040 
1041 			rtl::OUString aOUExpandedExtensionPath = Databases::expandURL( aExtensionRegistryPath, xContext );
1042 			rtl::OString aExpandedExtensionPath = rtl::OUStringToOString( aOUExpandedExtensionPath, osl_getThreadTextEncoding() );
1043 
1044 			parString[last++] = "ExtensionPath";
1045 			parString[last++] = rtl::OString('\'') + aExpandedExtensionPath + rtl::OString('\'');
1046 
1047 			// ExtensionId
1048 			rtl::OString aPureExtensionId;
1049 			sal_Int32 iSlash = aPath.indexOf( '/' );
1050 			if( iSlash != -1 )
1051 				aPureExtensionId = aPath.copy( 0, iSlash );
1052 
1053 			parString[last++] = "ExtensionId";
1054 			parString[last++] = rtl::OString('\'') + aPureExtensionId + rtl::OString('\'');
1055 		}
1056 
1057 		for( int i = 0; i < last; ++i )
1058 			parameter[i] = parString[i].getStr();
1059 		parameter[last] = 0;
1060 
1061 		rtl::OUString xslURL = pDatabases->getInstallPathAsURL();
1062 
1063 		rtl::OString xslURLascii(
1064 			xslURL.getStr(),
1065 			xslURL.getLength(),
1066 			RTL_TEXTENCODING_UTF8);
1067 		xslURLascii += "main_transform.xsl";
1068 
1069         ugblData = &userData;
1070 
1071         xmlInitParser();
1072         xmlRegisterInputCallbacks(zipMatch, zipOpen, zipRead, uriClose);
1073         xmlRegisterInputCallbacks(helpMatch, helpOpen, helpRead, uriClose);
1074 		xmlRegisterInputCallbacks(fileMatch, fileOpen, fileRead, fileClose);
1075 		//xmlSetStructuredErrorFunc( NULL, (xmlStructuredErrorFunc)StructuredXMLErrorFunction );
1076 
1077         xsltStylesheetPtr cur =
1078             xsltParseStylesheetFile((const xmlChar *)xslURLascii.getStr());
1079 
1080         xmlDocPtr doc = xmlParseFile("vnd.sun.star.zip:/");
1081 
1082         xmlDocPtr res = xsltApplyStylesheet(cur, doc, parameter);
1083         if (res)
1084 		{
1085 			xmlChar *doc_txt_ptr=0;
1086 			int doc_txt_len;
1087 			xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, res, cur);
1088 			addToBuffer((const char*)doc_txt_ptr, doc_txt_len);
1089 			xmlFree(doc_txt_ptr);
1090         }
1091         xmlPopInputCallbacks();	//filePatch
1092         xmlPopInputCallbacks();	//helpPatch
1093         xmlPopInputCallbacks();	//zipMatch
1094         xmlFreeDoc(res);
1095         xmlFreeDoc(doc);
1096         xsltFreeStylesheet(cur);
1097 	}
1098 }
1099 
1100 
1101 InputStreamTransformer::~InputStreamTransformer()
1102 {
1103 	delete[] buffer;
1104 }
1105 
1106 
1107 Any SAL_CALL InputStreamTransformer::queryInterface( const Type& rType ) throw( RuntimeException )
1108 {
1109 	Any aRet = ::cppu::queryInterface( rType,
1110 									   SAL_STATIC_CAST( XInputStream*,this ),
1111 									   SAL_STATIC_CAST( XSeekable*,this ) );
1112 
1113 	return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
1114 }
1115 
1116 
1117 
1118 void SAL_CALL InputStreamTransformer::acquire( void ) throw()
1119 {
1120 	OWeakObject::acquire();
1121 }
1122 
1123 
1124 
1125 void SAL_CALL InputStreamTransformer::release( void ) throw()
1126 {
1127 	OWeakObject::release();
1128 }
1129 
1130 
1131 
1132 sal_Int32 SAL_CALL InputStreamTransformer::readBytes( Sequence< sal_Int8 >& aData,sal_Int32 nBytesToRead )
1133 	throw( NotConnectedException,
1134 		   BufferSizeExceededException,
1135 		   IOException,
1136 		   RuntimeException)
1137 {
1138 	osl::MutexGuard aGuard( m_aMutex );
1139 
1140 	int curr,available_ = len-pos;
1141 	if( nBytesToRead <= available_ )
1142 		curr = nBytesToRead;
1143 	else
1144 		curr = available_;
1145 
1146 	if( 0 <= curr && aData.getLength() < curr )
1147 		aData.realloc( curr );
1148 
1149 	for( int k = 0; k < curr; ++k )
1150 		aData[k] = buffer[pos++];
1151 
1152 	return curr > 0 ? curr : 0;
1153 }
1154 
1155 
1156 sal_Int32 SAL_CALL InputStreamTransformer::readSomeBytes( Sequence< sal_Int8 >& aData,sal_Int32 nMaxBytesToRead )
1157 	throw( NotConnectedException,
1158 		   BufferSizeExceededException,
1159 		   IOException,
1160 		   RuntimeException)
1161 {
1162 	return readBytes( aData,nMaxBytesToRead );
1163 }
1164 
1165 
1166 
1167 void SAL_CALL InputStreamTransformer::skipBytes( sal_Int32 nBytesToSkip ) throw( NotConnectedException,
1168 																				 BufferSizeExceededException,
1169 																				 IOException,
1170 																				 RuntimeException )
1171 {
1172 	osl::MutexGuard aGuard( m_aMutex );
1173 	while( nBytesToSkip-- ) ++pos;
1174 }
1175 
1176 
1177 
1178 sal_Int32 SAL_CALL InputStreamTransformer::available( void ) throw( NotConnectedException,
1179 																	IOException,
1180 																	RuntimeException )
1181 {
1182 	osl::MutexGuard aGuard( m_aMutex );
1183 	return len-pos > 0 ? len - pos : 0 ;
1184 }
1185 
1186 
1187 
1188 void SAL_CALL InputStreamTransformer::closeInput( void ) throw( NotConnectedException,
1189 																IOException,
1190 																RuntimeException )
1191 {
1192 }
1193 
1194 
1195 
1196 void SAL_CALL InputStreamTransformer::seek( sal_Int64 location ) throw( IllegalArgumentException,
1197 																		IOException,
1198 																		RuntimeException )
1199 {
1200 	osl::MutexGuard aGuard( m_aMutex );
1201 	if( location < 0 )
1202 		throw IllegalArgumentException();
1203 	else
1204 		pos = sal::static_int_cast<sal_Int32>( location );
1205 
1206 	if( pos > len )
1207 		pos = len;
1208 }
1209 
1210 
1211 
1212 sal_Int64 SAL_CALL InputStreamTransformer::getPosition( void ) throw( IOException,
1213 																	  RuntimeException )
1214 {
1215 	osl::MutexGuard aGuard( m_aMutex );
1216 	return sal_Int64( pos );
1217 }
1218 
1219 
1220 
1221 sal_Int64 SAL_CALL InputStreamTransformer::getLength( void ) throw( IOException,RuntimeException )
1222 {
1223 	osl::MutexGuard aGuard( m_aMutex );
1224 
1225 	return len;
1226 }
1227 
1228 
1229 void InputStreamTransformer::addToBuffer( const char* buffer_,int len_ )
1230 {
1231 	osl::MutexGuard aGuard( m_aMutex );
1232 
1233 	char* tmp = buffer;
1234 	buffer = new char[ len+len_ ];
1235 	rtl_copyMemory( (void*)(buffer),(void*)(tmp),sal_uInt32( len ) );
1236 	rtl_copyMemory( (void*)(buffer+len),(void*)(buffer_),sal_uInt32( len_ ) );
1237 	delete[] tmp;
1238 	len += len_;
1239 }
1240