merge the formfield patch from ooo-build
[ooovba.git] / xmlhelp / source / cxxhelp / provider / urlparameter.cxx
blobf597429a3ef04a942583825beb7f129b5fd637cf
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: urlparameter.cxx,v $
10 * $Revision: 1.44 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_xmlhelp.hxx"
34 #define WORKAROUND_98119
36 #ifdef WORKAROUND_98119
37 #include "bufferedinputstream.hxx"
38 #endif
40 #include <string.h>
41 #ifndef _VOS_DIAGNOSE_HXX_
42 #include <vos/diagnose.hxx>
43 #endif
44 #include <osl/thread.h>
45 #include <rtl/memory.h>
46 #include <osl/file.hxx>
47 #include <cppuhelper/weak.hxx>
48 #include <cppuhelper/queryinterface.hxx>
49 #include <comphelper/processfactory.hxx>
50 #include <rtl/uri.hxx>
51 #include <rtl/ustrbuf.hxx>
52 #include <libxslt/xslt.h>
53 #include <libxslt/transform.h>
54 #include <libxslt/xsltutils.h>
55 #include "db.hxx"
56 #include <com/sun/star/io/XActiveDataSink.hpp>
57 #include <com/sun/star/io/XInputStream.hpp>
58 #include <com/sun/star/io/XSeekable.hpp>
59 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
60 #include <com/sun/star/ucb/OpenMode.hpp>
61 #include <com/sun/star/ucb/XCommandProcessor.hpp>
62 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
63 #include <com/sun/star/ucb/XContentIdentifier.hpp>
64 #include <com/sun/star/ucb/XContentProvider.hpp>
65 #include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
66 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
67 #include <com/sun/star/beans/XPropertySet.hpp>
69 #include "urlparameter.hxx"
70 #include "databases.hxx"
72 namespace chelp {
74 inline bool ascii_isDigit( sal_Unicode ch )
76 return ((ch >= 0x0030) && (ch <= 0x0039));
79 inline bool ascii_isLetter( sal_Unicode ch )
81 return ( ( (ch >= 0x0041) && (ch <= 0x005A) ) ||
82 ( (ch >= 0x0061) && (ch <= 0x007A) ) );
85 inline bool isLetterOrDigit( sal_Unicode ch )
87 return ascii_isLetter( ch ) || ascii_isDigit( ch );
92 using namespace cppu;
93 using namespace com::sun::star::io;
94 using namespace com::sun::star::uno;
95 using namespace com::sun::star::lang;
96 using namespace com::sun::star::ucb;
97 using namespace com::sun::star::beans;
98 using namespace com::sun::star::container;
99 using namespace berkeleydbproxy;
100 using namespace chelp;
103 URLParameter::URLParameter( const rtl::OUString& aURL,
104 Databases* pDatabases )
105 throw( com::sun::star::ucb::IllegalIdentifierException )
106 : m_pDatabases( pDatabases ),
107 m_aURL( aURL )
109 init( false );
110 parse();
114 bool URLParameter::isErrorDocument()
116 bool bErrorDoc = false;
118 if( isFile() )
120 Reference< XHierarchicalNameAccess > xNA =
121 m_pDatabases->findJarFileForPath( get_jar(), get_language(), get_path() );
122 bErrorDoc = !xNA.is();
125 return bErrorDoc;
129 rtl::OString URLParameter::getByName( const char* par )
131 rtl::OUString val;
133 if( strcmp( par,"Program" ) == 0 )
134 val = get_program();
135 else if( strcmp( par,"Database" ) == 0 )
136 val = get_module();
137 else if( strcmp( par,"DatabasePar" ) == 0 )
138 val = get_dbpar();
139 else if( strcmp( par,"Id" ) == 0 )
140 val = get_id();
141 else if( strcmp( par,"Path" ) == 0 )
142 val = get_path();
143 else if( strcmp( par,"Language" ) == 0 )
144 val = get_language();
145 else if( strcmp( par,"System" ) == 0 )
146 val = get_system();
147 else if( strcmp( par,"HelpPrefix" ) == 0 )
148 val = get_prefix();
150 return rtl::OString( val.getStr(),val.getLength(),RTL_TEXTENCODING_UTF8 );
154 rtl::OUString URLParameter::get_id()
156 if( m_aId.compareToAscii("start") == 0 )
157 { // module is set
158 StaticModuleInformation* inf =
159 m_pDatabases->getStaticInformationForModule( get_module(),
160 get_language() );
161 if( inf )
162 m_aId = inf->get_id();
164 m_bStart = true;
167 return m_aId;
170 rtl::OUString URLParameter::get_tag()
172 if( isFile() )
173 return get_the_tag();
174 else
175 return m_aTag;
179 rtl::OUString URLParameter::get_title()
181 if( isFile() )
182 return get_the_title();
183 else if( m_aModule.compareToAscii("") != 0 )
185 StaticModuleInformation* inf =
186 m_pDatabases->getStaticInformationForModule( get_module(),
187 get_language() );
188 if( inf )
189 m_aTitle = inf->get_title();
191 else // This must be the root
192 m_aTitle = rtl::OUString::createFromAscii("root");
194 return m_aTitle;
198 rtl::OUString URLParameter::get_language()
200 if( m_aLanguage.getLength() == 0 )
201 return m_aDefaultLanguage;
203 return m_aLanguage;
207 rtl::OUString URLParameter::get_program()
209 if( ! m_aProgram.getLength() )
211 StaticModuleInformation* inf =
212 m_pDatabases->getStaticInformationForModule( get_module(),
213 get_language() );
214 if( inf )
215 m_aProgram = inf->get_program();
217 return m_aProgram;
221 void URLParameter::init( bool bDefaultLanguageIsInitialized )
223 (void)bDefaultLanguageIsInitialized;
225 m_bBerkeleyRead = false;
226 m_bStart = false;
227 m_bUseDB = true;
228 m_nHitCount = 100; // The default maximum hitcount
232 rtl::OUString URLParameter::get_the_tag()
234 if(m_bUseDB) {
235 if( ! m_bBerkeleyRead )
236 readBerkeley();
238 m_bBerkeleyRead = true;
240 return m_aTag;
242 else
243 return rtl::OUString();
248 rtl::OUString URLParameter::get_the_path()
250 if(m_bUseDB) {
251 if( ! m_bBerkeleyRead )
252 readBerkeley();
253 m_bBerkeleyRead = true;
255 return m_aPath;
257 else
258 return get_id();
263 rtl::OUString URLParameter::get_the_title()
265 if(m_bUseDB) {
266 if( ! m_bBerkeleyRead )
267 readBerkeley();
268 m_bBerkeleyRead = true;
270 return m_aTitle;
272 else
273 return rtl::OUString();
277 rtl::OUString URLParameter::get_the_jar()
279 if(m_bUseDB) {
280 if( ! m_bBerkeleyRead )
281 readBerkeley();
282 m_bBerkeleyRead = true;
284 return m_aJar;
286 else
287 return get_module() + rtl::OUString::createFromAscii(".jar");
293 void URLParameter::readBerkeley()
295 static rtl::OUString aQuestionMark( rtl::OUString::createFromAscii( "?" ) );
297 if( get_id().compareToAscii("") == 0 )
298 return;
300 rtl::OUString aModule = get_module();
301 rtl::OUString aLanguage = get_language();
303 DataBaseIterator aDbIt( *m_pDatabases, aModule, aLanguage, false );
304 bool bSuccess = false;
306 int nSize = 0;
307 const sal_Char* pData = NULL;
309 Dbt data;
310 DBData aDBData;
311 rtl::OUString aExtensionPath;
312 while( true )
314 Db* db = aDbIt.nextDb( &aExtensionPath );
315 if( !db )
316 break;
318 rtl::OString keyStr( m_aId.getStr(),m_aId.getLength(),RTL_TEXTENCODING_UTF8 );
320 DBHelp* pDBHelp = db->getDBHelp();
321 if( pDBHelp != NULL )
323 bSuccess = pDBHelp->getValueForKey( keyStr, aDBData );
324 if( bSuccess )
326 nSize = aDBData.getSize();
327 pData = aDBData.getData();
328 break;
331 else
333 Dbt key( static_cast< void* >( const_cast< sal_Char* >( keyStr.getStr() ) ),
334 keyStr.getLength() );
335 int err = db->get( 0,&key,&data,0 );
336 if( err == 0 )
338 bSuccess = true;
339 nSize = data.get_size();
340 pData = static_cast<sal_Char*>( data.get_data() );
341 break;
346 if( bSuccess )
348 DbtToStringConverter converter( pData, nSize );
349 m_aTitle = converter.getTitle();
350 m_pDatabases->replaceName( m_aTitle );
351 m_aPath = converter.getFile();
352 m_aJar = converter.getDatabase();
353 if( aExtensionPath.getLength() > 0 )
355 rtl::OUStringBuffer aExtendedJarStrBuf;
356 aExtendedJarStrBuf.append( aQuestionMark );
357 aExtendedJarStrBuf.append( aExtensionPath );
358 aExtendedJarStrBuf.append( aQuestionMark );
359 aExtendedJarStrBuf.append( m_aJar );
360 m_aJar = aExtendedJarStrBuf.makeStringAndClear();
362 m_aTag = converter.getHash();
368 // Class encapsulating the transformation of the XInputStream to XHTML
371 class InputStreamTransformer
372 : public OWeakObject,
373 public XInputStream,
374 public XSeekable
376 public:
378 InputStreamTransformer( URLParameter* urlParam,
379 Databases* pDatatabases,
380 bool isRoot = false );
382 ~InputStreamTransformer();
384 virtual Any SAL_CALL queryInterface( const Type& rType ) throw( RuntimeException );
385 virtual void SAL_CALL acquire( void ) throw();
386 virtual void SAL_CALL release( void ) throw();
388 virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData,sal_Int32 nBytesToRead )
389 throw( NotConnectedException,
390 BufferSizeExceededException,
391 IOException,
392 RuntimeException);
394 virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData,sal_Int32 nMaxBytesToRead )
395 throw( NotConnectedException,
396 BufferSizeExceededException,
397 IOException,
398 RuntimeException);
400 virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) throw( NotConnectedException,
401 BufferSizeExceededException,
402 IOException,
403 RuntimeException );
405 virtual sal_Int32 SAL_CALL available( void ) throw( NotConnectedException,
406 IOException,
407 RuntimeException );
409 virtual void SAL_CALL closeInput( void ) throw( NotConnectedException,
410 IOException,
411 RuntimeException );
413 virtual void SAL_CALL seek( sal_Int64 location ) throw( IllegalArgumentException,
414 IOException,
415 RuntimeException );
417 virtual sal_Int64 SAL_CALL getPosition( void ) throw( IOException,RuntimeException );
419 virtual sal_Int64 SAL_CALL getLength( void ) throw( IOException,RuntimeException );
421 void addToBuffer( const char* buffer,int len );
423 sal_Int8* getData() const { return (sal_Int8*) buffer; }
425 sal_Int32 getLen() const { return sal_Int32( len ); }
427 private:
429 osl::Mutex m_aMutex;
431 int len,pos;
432 char *buffer;
437 void URLParameter::open( const Reference< XMultiServiceFactory >& rxSMgr,
438 const Command& aCommand,
439 sal_Int32 CommandId,
440 const Reference< XCommandEnvironment >& Environment,
441 const Reference< XOutputStream >& xDataSink )
443 (void)rxSMgr;
444 (void)aCommand;
445 (void)CommandId;
446 (void)Environment;
448 if( ! xDataSink.is() )
449 return;
451 if( isPicture() )
453 Reference< XInputStream > xStream;
454 Reference< XHierarchicalNameAccess > xNA =
455 m_pDatabases->jarFile( rtl::OUString::createFromAscii( "picture.jar" ),
456 get_language() );
458 rtl::OUString path = get_path();
459 if( xNA.is() )
463 Any aEntry = xNA->getByHierarchicalName( path );
464 Reference< XActiveDataSink > xSink;
465 if( ( aEntry >>= xSink ) && xSink.is() )
466 xStream = xSink->getInputStream();
468 catch ( NoSuchElementException & )
472 if( xStream.is() )
474 sal_Int32 ret;
475 Sequence< sal_Int8 > aSeq( 4096 );
476 while( true )
480 ret = xStream->readBytes( aSeq,4096 );
481 xDataSink->writeBytes( aSeq );
482 if( ret < 4096 )
483 break;
485 catch( const Exception& )
487 break;
492 else
494 // a standard document or else an active help text, plug in the new input stream
495 InputStreamTransformer* p = new InputStreamTransformer( this,m_pDatabases,isRoot() );
498 xDataSink->writeBytes( Sequence< sal_Int8 >( p->getData(),p->getLen() ) );
500 catch( const Exception& )
503 delete p;
505 xDataSink->closeOutput();
510 void URLParameter::open( const Reference< XMultiServiceFactory >& rxSMgr,
511 const Command& aCommand,
512 sal_Int32 CommandId,
513 const Reference< XCommandEnvironment >& Environment,
514 const Reference< XActiveDataSink >& xDataSink )
516 (void)rxSMgr;
517 (void)aCommand;
518 (void)CommandId;
519 (void)Environment;
521 if( isPicture() )
523 Reference< XInputStream > xStream;
524 Reference< XHierarchicalNameAccess > xNA =
525 m_pDatabases->jarFile( rtl::OUString::createFromAscii( "picture.jar" ),
526 get_language() );
528 rtl::OUString path = get_path();
529 if( xNA.is() )
533 Any aEntry = xNA->getByHierarchicalName( path );
534 Reference< XActiveDataSink > xSink;
535 if( ( aEntry >>= xSink ) && xSink.is() )
536 xStream = xSink->getInputStream();
538 catch ( NoSuchElementException & )
542 #ifdef WORKAROUND_98119
543 xDataSink->setInputStream( turnToSeekable(xStream) );
544 #else
545 xDataSink->setInputStream( xStream );
546 #endif
548 else
549 // a standard document or else an active help text, plug in the new input stream
550 xDataSink->setInputStream( new InputStreamTransformer( this,m_pDatabases,isRoot() ) );
554 // #include <stdio.h>
556 void URLParameter::parse() throw( com::sun::star::ucb::IllegalIdentifierException )
558 // fprintf(stdout,"url send to xmlhelp: %s\n",(rtl::OUStringToOString(m_aURL,RTL_TEXTENCODING_UTF8).getStr()));
559 m_aExpr = m_aURL;
561 sal_Int32 lstIdx = m_aExpr.lastIndexOf( sal_Unicode( '#' ) );
562 if( lstIdx != -1 )
563 m_aExpr = m_aExpr.copy( 0,lstIdx );
565 if( ! scheme() ||
566 ! name( module() ) ||
567 ! query() ||
568 ! m_aLanguage.getLength() ||
569 ! m_aSystem.getLength() )
570 throw com::sun::star::ucb::IllegalIdentifierException();
574 bool URLParameter::scheme()
576 // Correct extension help links as sometimes the
577 // module is missing resulting in a misformed URL
578 if( m_aExpr.compareToAscii( "vnd.sun.star.help:///", 21 ) == 0 )
580 sal_Int32 nLen = m_aExpr.getLength();
581 rtl::OUString aLastStr = m_aExpr.copy( nLen - 6 );
582 if( aLastStr.compareToAscii( "DbPAR=" ) == 0 )
584 rtl::OUString aNewExpr = m_aExpr.copy( 0, 20 );
585 rtl::OUString aSharedStr = rtl::OUString::createFromAscii( "shared" );
586 aNewExpr += aSharedStr;
587 aNewExpr += m_aExpr.copy( 20 );
588 aNewExpr += aSharedStr;
589 m_aExpr = aNewExpr;
593 for( sal_Int32 nPrefixLen = 20 ; nPrefixLen >= 18 ; --nPrefixLen )
595 if( m_aExpr.compareToAscii( "vnd.sun.star.help://", nPrefixLen ) == 0 )
597 m_aExpr = m_aExpr.copy( nPrefixLen );
598 return true;
601 return false;
605 bool URLParameter::module()
607 sal_Int32 idx = 0,length = m_aExpr.getLength();
609 while( idx < length && isLetterOrDigit( (m_aExpr.getStr())[idx] ) )
610 ++idx;
612 if( idx != 0 )
614 m_aModule = m_aExpr.copy( 0,idx );
615 m_aExpr = m_aExpr.copy( idx );
616 return true;
618 else
619 return false;
624 bool URLParameter::name( bool modulePresent )
626 // if modulepresent, a name may be present, but must not
628 sal_Int32 length = m_aExpr.getLength();
630 if( length != 0 && (m_aExpr.getStr())[0] == sal_Unicode( '/' ) )
632 sal_Int32 idx = 1;
633 while( idx < length && (m_aExpr.getStr())[idx] != '?' )
634 // ( isLetterOrDigit( (m_aExpr.getStr())[idx] )
635 // || (m_aExpr.getStr())[idx] == '/'
636 // || (m_aExpr.getStr())[idx] == '.' ))
637 ++idx;
639 if( idx != 1 && ! modulePresent )
640 return false;
641 else
643 m_aId = m_aExpr.copy( 1,idx-1 );
644 m_aExpr = m_aExpr.copy( idx );
648 // fprintf(stdout,"id %s\n",(rtl::OUStringToOString(m_aId,RTL_TEXTENCODING_UTF8).getStr()));
649 return true;
653 bool URLParameter::query()
655 rtl::OUString query_;
657 if( ! m_aExpr.getLength() )
658 return true;
659 else if( (m_aExpr.getStr())[0] == sal_Unicode( '?' ) )
660 query_ = m_aExpr.copy( 1 ).trim();
661 else
662 return false;
665 bool ret = true;
666 sal_Int32 delimIdx,equalIdx;
667 rtl::OUString parameter,value;
669 while( query_.getLength() != 0 )
671 delimIdx = query_.indexOf( sal_Unicode( '&' ) );
672 equalIdx = query_.indexOf( sal_Unicode( '=' ) );
673 parameter = query_.copy( 0,equalIdx ).trim();
674 if( delimIdx == -1 )
676 value = query_.copy( equalIdx + 1 ).trim();
677 query_ = rtl::OUString();
679 else
681 value = query_.copy( equalIdx+1,delimIdx - equalIdx - 1 ).trim();
682 query_ = query_.copy( delimIdx+1 ).trim();
685 if( parameter.compareToAscii( "Language" ) == 0 )
686 m_aLanguage = value;
687 else if( parameter.compareToAscii( "Device" ) == 0 )
688 m_aDevice = value;
689 else if( parameter.compareToAscii( "Program" ) == 0 )
690 m_aProgram = value;
691 else if( parameter.compareToAscii( "Eid" ) == 0 )
692 m_aEid = value;
693 else if( parameter.compareToAscii( "UseDB" ) == 0 )
694 m_bUseDB = ! ( value.compareToAscii("no") == 0 );
695 else if( parameter.compareToAscii( "DbPAR" ) == 0 )
696 m_aDbPar = value;
697 else if( parameter.compareToAscii( "Query" ) == 0 )
699 if( ! m_aQuery.getLength() )
700 m_aQuery = value;
701 else
702 m_aQuery += ( rtl::OUString::createFromAscii( " " ) + value );
704 else if( parameter.compareToAscii( "Scope" ) == 0 )
705 m_aScope = value;
706 else if( parameter.compareToAscii( "System" ) == 0 )
707 m_aSystem = value;
708 else if( parameter.compareToAscii( "HelpPrefix" ) == 0 )
709 m_aPrefix = rtl::Uri::decode(
710 value,
711 rtl_UriDecodeWithCharset,
712 RTL_TEXTENCODING_UTF8 );
713 else if( parameter.compareToAscii( "HitCount" ) == 0 )
714 m_nHitCount = value.toInt32();
715 else if( parameter.compareToAscii( "Active" ) == 0 )
716 m_aActive = value;
717 else
718 ret = false;
721 return ret;
724 struct UserData {
726 UserData( InputStreamTransformer* pTransformer,
727 URLParameter* pInitial,
728 Databases* pDatabases )
729 : m_pTransformer( pTransformer ),
730 m_pDatabases( pDatabases ),
731 m_pInitial( pInitial )
735 InputStreamTransformer* m_pTransformer;
736 Databases* m_pDatabases;
737 URLParameter* m_pInitial;
740 UserData *ugblData = 0;
742 extern "C" {
744 static int
745 fileMatch(const char * URI) {
746 if ((URI != NULL) && !strncmp(URI, "file:/", 6))
747 return 1;
748 return 0;
751 static int
752 zipMatch(const char * URI) {
753 if ((URI != NULL) && !strncmp(URI, "vnd.sun.star.zip:/", 18))
754 return 1;
755 return 0;
758 static int
759 helpMatch(const char * URI) {
760 if ((URI != NULL) && !strncmp(URI, "vnd.sun.star.help:/", 19))
761 return 1;
762 return 0;
765 static void *
766 fileOpen(const char *URI) {
767 osl::File *pRet = new osl::File(rtl::OUString(URI, strlen(URI), RTL_TEXTENCODING_UTF8));
768 pRet->open(OpenFlag_Read);
769 return pRet;
772 static void *
773 zipOpen(const char * /*URI*/) {
774 rtl::OUString language,jar,path;
776 if( ugblData->m_pInitial->get_eid().getLength() )
777 return (void*)(new Reference< XHierarchicalNameAccess >);
778 else
780 jar = ugblData->m_pInitial->get_jar();
781 language = ugblData->m_pInitial->get_language();
782 path = ugblData->m_pInitial->get_path();
785 Reference< XHierarchicalNameAccess > xNA =
786 ugblData->m_pDatabases->findJarFileForPath( jar, language, path );
788 Reference< XInputStream > xInputStream;
790 if( xNA.is() )
794 Any aEntry = xNA->getByHierarchicalName( path );
795 Reference< XActiveDataSink > xSink;
796 if( ( aEntry >>= xSink ) && xSink.is() )
797 xInputStream = xSink->getInputStream();
799 catch ( NoSuchElementException & )
804 if( xInputStream.is() )
806 return new Reference<XInputStream>(xInputStream);
808 return 0;
811 static void *
812 helpOpen(const char * URI) {
813 rtl::OUString language,jar,path;
815 URLParameter urlpar( rtl::OUString::createFromAscii( URI ),
816 ugblData->m_pDatabases );
818 jar = urlpar.get_jar();
819 language = urlpar.get_language();
820 path = urlpar.get_path();
822 Reference< XHierarchicalNameAccess > xNA =
823 ugblData->m_pDatabases->findJarFileForPath( jar, language, path );
825 Reference< XInputStream > xInputStream;
827 if( xNA.is() )
831 Any aEntry = xNA->getByHierarchicalName( path );
832 Reference< XActiveDataSink > xSink;
833 if( ( aEntry >>= xSink ) && xSink.is() )
834 xInputStream = xSink->getInputStream();
836 catch ( NoSuchElementException & )
841 if( xInputStream.is() )
842 return new Reference<XInputStream>(xInputStream);
843 return 0;
846 static int
847 helpRead(void * context, char * buffer, int len) {
848 Reference< XInputStream > *pRef = (Reference< XInputStream >*)context;
850 Sequence< sal_Int8 > aSeq;
851 len = (*pRef)->readBytes( aSeq,len);
852 memcpy(buffer, aSeq.getConstArray(), len);
854 return len;
857 static int
858 zipRead(void * context, char * buffer, int len) {
859 if( ugblData->m_pInitial->get_eid().getLength() )
861 ugblData->m_pDatabases->popupDocument( ugblData->m_pInitial,&buffer,&len);
862 return len;
864 else
865 return helpRead(context, buffer, len);
868 static int
869 fileRead(void * context, char * buffer, int len) {
870 int nRead = 0;
871 osl::File *pFile = (osl::File*)context;
872 if (pFile)
874 sal_uInt64 uRead = 0;
875 if (osl::FileBase::E_None == pFile->read(buffer, len, uRead))
876 nRead = static_cast<int>(uRead);
878 return nRead;
881 static int
882 uriClose(void * context) {
883 Reference< XInputStream > *pRef = (Reference< XInputStream >*)context;
884 delete pRef;
885 return 0;
888 static int
889 fileClose(void * context) {
890 osl::File *pFile = (osl::File*)context;
891 if (pFile)
893 pFile->close();
894 delete pFile;
896 return 0;
899 } // extern "C"
902 // For debugging only
903 extern "C" void StructuredXMLErrorFunction(void *userData, xmlErrorPtr error)
905 (void)userData;
906 (void)error;
908 // Reset error handler
909 xmlSetStructuredErrorFunc( NULL, NULL );
913 InputStreamTransformer::InputStreamTransformer( URLParameter* urlParam,
914 Databases* pDatabases,
915 bool isRoot )
916 : len( 0 ),
917 pos( 0 ),
918 buffer( new char[1] ) // Initializing with one element to avoid gcc compiler warning
920 if( isRoot )
922 delete[] buffer;
923 pDatabases->cascadingStylesheet( urlParam->get_language(),
924 &buffer,
925 &len );
927 else if( urlParam->isActive() )
929 delete[] buffer;
930 pDatabases->setActiveText( urlParam->get_module(),
931 urlParam->get_language(),
932 urlParam->get_id(),
933 &buffer,
934 &len );
936 else
938 UserData userData( this,urlParam,pDatabases );
940 // Uses the implementation detail, that rtl::OString::getStr returns a zero terminated character-array
942 const char* parameter[47];
943 rtl::OString parString[46];
944 int last = 0;
946 parString[last++] = "Program";
947 rtl::OString aPureProgramm( urlParam->getByName( "Program" ) );
948 parString[last++] = rtl::OString('\'') + aPureProgramm + rtl::OString('\'');
949 parString[last++] = "Database";
950 parString[last++] = rtl::OString('\'') + urlParam->getByName( "DatabasePar" ) + rtl::OString('\'');
951 parString[last++] = "Id";
952 parString[last++] = rtl::OString('\'') + urlParam->getByName( "Id" ) + rtl::OString('\'');
953 parString[last++] = "Path";
954 rtl::OString aPath( urlParam->getByName( "Path" ) );
955 parString[last++] = rtl::OString('\'') + aPath + rtl::OString('\'');
957 rtl::OString aPureLanguage = urlParam->getByName( "Language" );
958 parString[last++] = "Language";
959 parString[last++] = rtl::OString('\'') + aPureLanguage + rtl::OString('\'');
960 parString[last++] = "System";
961 parString[last++] = rtl::OString('\'') + urlParam->getByName( "System" ) + rtl::OString('\'');
962 parString[last++] = "productname";
963 parString[last++] = rtl::OString('\'') + rtl::OString(
964 pDatabases->getProductName().getStr(),
965 pDatabases->getProductName().getLength(),
966 RTL_TEXTENCODING_UTF8 ) + rtl::OString('\'');
967 parString[last++] = "productversion";
968 parString[last++] = rtl::OString('\'') +
969 rtl::OString( pDatabases->getProductVersion().getStr(),
970 pDatabases->getProductVersion().getLength(),
971 RTL_TEXTENCODING_UTF8 ) + rtl::OString('\'');
973 parString[last++] = "imgrepos";
974 parString[last++] = rtl::OString('\'') + pDatabases->getImagesZipFileURL() + rtl::OString('\'');
975 parString[last++] = "hp";
976 parString[last++] = rtl::OString('\'') + urlParam->getByName( "HelpPrefix" ) + rtl::OString('\'');
978 if( parString[last-1].getLength() )
980 parString[last++] = "sm";
981 parString[last++] = "'vnd.sun.star.help%3A%2F%2F'";
982 parString[last++] = "qm";
983 parString[last++] = "'%3F'";
984 parString[last++] = "es";
985 parString[last++] = "'%3D'";
986 parString[last++] = "am";
987 parString[last++] = "'%26'";
988 parString[last++] = "cl";
989 parString[last++] = "'%3A'";
990 parString[last++] = "sl";
991 parString[last++] = "'%2F'";
992 parString[last++] = "hm";
993 parString[last++] = "'%23'";
994 parString[last++] = "cs";
995 parString[last++] = "'css'";
997 parString[last++] = "vendorname";
998 parString[last++] = rtl::OString('\'') +
999 rtl::OString( pDatabases->getVendorName().getStr(),
1000 pDatabases->getVendorName().getLength(),
1001 RTL_TEXTENCODING_UTF8 ) + rtl::OString('\'');
1002 parString[last++] = "vendorversion";
1003 parString[last++] = rtl::OString('\'') +
1004 rtl::OString( pDatabases->getVendorVersion().getStr(),
1005 pDatabases->getVendorVersion().getLength(),
1006 RTL_TEXTENCODING_UTF8 ) + rtl::OString('\'');
1007 parString[last++] = "vendorshort";
1008 parString[last++] = rtl::OString('\'') +
1009 rtl::OString( pDatabases->getVendorShort().getStr(),
1010 pDatabases->getVendorShort().getLength(),
1011 RTL_TEXTENCODING_UTF8 ) + rtl::OString('\'');
1014 // Do we need to add extension path?
1015 ::rtl::OUString aExtensionPath;
1016 rtl::OUString aJar = urlParam->get_jar();
1018 bool bAddExtensionPath = false;
1019 sal_Int32 nQuestionMark1 = aJar.indexOf( sal_Unicode('?') );
1020 sal_Int32 nQuestionMark2 = aJar.lastIndexOf( sal_Unicode('?') );
1021 if( nQuestionMark1 != -1 && nQuestionMark2 != -1 && nQuestionMark1 != nQuestionMark2 )
1023 aExtensionPath = aJar.copy( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 );
1024 bAddExtensionPath = true;
1026 else
1028 // Path not yet specified, search directly
1029 Reference< XHierarchicalNameAccess > xNA = pDatabases->findJarFileForPath
1030 ( aJar, urlParam->get_language(), urlParam->get_path(), &aExtensionPath );
1031 if( xNA.is() && aExtensionPath.getLength() )
1032 bAddExtensionPath = true;
1035 if( bAddExtensionPath )
1037 Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
1038 Reference< XPropertySet > xProps( xFactory, UNO_QUERY );
1039 OSL_ASSERT( xProps.is() );
1040 Reference< XComponentContext > xContext;
1041 if (xProps.is())
1043 xProps->getPropertyValue(
1044 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext;
1046 if( !xContext.is() )
1048 throw RuntimeException(
1049 ::rtl::OUString::createFromAscii( "InputStreamTransformer::InputStreamTransformer(), no XComponentContext" ),
1050 Reference< XInterface >() );
1053 rtl::OUString aOUExpandedExtensionPath = Databases::expandURL( aExtensionPath, xContext );
1054 rtl::OString aExpandedExtensionPath = rtl::OUStringToOString( aOUExpandedExtensionPath, osl_getThreadTextEncoding() );
1056 parString[last++] = "ExtensionPath";
1057 parString[last++] = rtl::OString('\'') + aExpandedExtensionPath + rtl::OString('\'');
1059 // ExtensionId
1060 rtl::OString aPureExtensionId;
1061 sal_Int32 iSlash = aPath.indexOf( '/' );
1062 if( iSlash != -1 )
1063 aPureExtensionId = aPath.copy( 0, iSlash );
1065 parString[last++] = "ExtensionId";
1066 parString[last++] = rtl::OString('\'') + aPureExtensionId + rtl::OString('\'');
1069 for( int i = 0; i < last; ++i )
1070 parameter[i] = parString[i].getStr();
1071 parameter[last] = 0;
1073 rtl::OUString xslURL = pDatabases->getInstallPathAsURL();
1075 rtl::OString xslURLascii(
1076 xslURL.getStr(),
1077 xslURL.getLength(),
1078 RTL_TEXTENCODING_UTF8);
1079 xslURLascii += "main_transform.xsl";
1081 ugblData = &userData;
1083 xmlRegisterInputCallbacks(zipMatch, zipOpen, zipRead, uriClose);
1084 xmlRegisterInputCallbacks(helpMatch, helpOpen, helpRead, uriClose);
1085 xmlRegisterInputCallbacks(fileMatch, fileOpen, fileRead, fileClose);
1086 //xmlSetStructuredErrorFunc( NULL, (xmlStructuredErrorFunc)StructuredXMLErrorFunction );
1088 xsltStylesheetPtr cur =
1089 xsltParseStylesheetFile((const xmlChar *)xslURLascii.getStr());
1091 xmlDocPtr doc = xmlParseFile("vnd.sun.star.zip:/");
1093 xmlDocPtr res = xsltApplyStylesheet(cur, doc, parameter);
1094 if (res)
1096 xmlChar *doc_txt_ptr=0;
1097 int doc_txt_len;
1098 xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, res, cur);
1099 addToBuffer((const char*)doc_txt_ptr, doc_txt_len);
1100 xmlFree(doc_txt_ptr);
1102 xmlPopInputCallbacks(); //filePatch
1103 xmlPopInputCallbacks(); //helpPatch
1104 xmlPopInputCallbacks(); //zipMatch
1105 xmlFreeDoc(res);
1106 xmlFreeDoc(doc);
1107 xsltFreeStylesheet(cur);
1112 InputStreamTransformer::~InputStreamTransformer()
1114 delete[] buffer;
1118 Any SAL_CALL InputStreamTransformer::queryInterface( const Type& rType ) throw( RuntimeException )
1120 Any aRet = ::cppu::queryInterface( rType,
1121 SAL_STATIC_CAST( XInputStream*,this ),
1122 SAL_STATIC_CAST( XSeekable*,this ) );
1124 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
1129 void SAL_CALL InputStreamTransformer::acquire( void ) throw()
1131 OWeakObject::acquire();
1136 void SAL_CALL InputStreamTransformer::release( void ) throw()
1138 OWeakObject::release();
1143 sal_Int32 SAL_CALL InputStreamTransformer::readBytes( Sequence< sal_Int8 >& aData,sal_Int32 nBytesToRead )
1144 throw( NotConnectedException,
1145 BufferSizeExceededException,
1146 IOException,
1147 RuntimeException)
1149 osl::MutexGuard aGuard( m_aMutex );
1151 int curr,available_ = len-pos;
1152 if( nBytesToRead <= available_ )
1153 curr = nBytesToRead;
1154 else
1155 curr = available_;
1157 if( 0 <= curr && aData.getLength() < curr )
1158 aData.realloc( curr );
1160 for( int k = 0; k < curr; ++k )
1161 aData[k] = buffer[pos++];
1163 return curr > 0 ? curr : 0;
1167 sal_Int32 SAL_CALL InputStreamTransformer::readSomeBytes( Sequence< sal_Int8 >& aData,sal_Int32 nMaxBytesToRead )
1168 throw( NotConnectedException,
1169 BufferSizeExceededException,
1170 IOException,
1171 RuntimeException)
1173 return readBytes( aData,nMaxBytesToRead );
1178 void SAL_CALL InputStreamTransformer::skipBytes( sal_Int32 nBytesToSkip ) throw( NotConnectedException,
1179 BufferSizeExceededException,
1180 IOException,
1181 RuntimeException )
1183 osl::MutexGuard aGuard( m_aMutex );
1184 while( nBytesToSkip-- ) ++pos;
1189 sal_Int32 SAL_CALL InputStreamTransformer::available( void ) throw( NotConnectedException,
1190 IOException,
1191 RuntimeException )
1193 osl::MutexGuard aGuard( m_aMutex );
1194 return len-pos > 0 ? len - pos : 0 ;
1199 void SAL_CALL InputStreamTransformer::closeInput( void ) throw( NotConnectedException,
1200 IOException,
1201 RuntimeException )
1207 void SAL_CALL InputStreamTransformer::seek( sal_Int64 location ) throw( IllegalArgumentException,
1208 IOException,
1209 RuntimeException )
1211 osl::MutexGuard aGuard( m_aMutex );
1212 if( location < 0 )
1213 throw IllegalArgumentException();
1214 else
1215 pos = sal::static_int_cast<sal_Int32>( location );
1217 if( pos > len )
1218 pos = len;
1223 sal_Int64 SAL_CALL InputStreamTransformer::getPosition( void ) throw( IOException,
1224 RuntimeException )
1226 osl::MutexGuard aGuard( m_aMutex );
1227 return sal_Int64( pos );
1232 sal_Int64 SAL_CALL InputStreamTransformer::getLength( void ) throw( IOException,RuntimeException )
1234 osl::MutexGuard aGuard( m_aMutex );
1236 return len;
1240 void InputStreamTransformer::addToBuffer( const char* buffer_,int len_ )
1242 osl::MutexGuard aGuard( m_aMutex );
1244 char* tmp = buffer;
1245 buffer = new char[ len+len_ ];
1246 rtl_copyMemory( (void*)(buffer),(void*)(tmp),sal_uInt32( len ) );
1247 rtl_copyMemory( (void*)(buffer+len),(void*)(buffer_),sal_uInt32( len_ ) );
1248 delete[] tmp;
1249 len += len_;