| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_xmlhelp.hxx" |
| |
| #define WORKAROUND_98119 |
| |
| #ifdef WORKAROUND_98119 |
| #include "bufferedinputstream.hxx" |
| #endif |
| |
| #include <string.h> |
| #ifndef _VOS_DIAGNOSE_HXX_ |
| #include <vos/diagnose.hxx> |
| #endif |
| #include <osl/thread.h> |
| #include <rtl/memory.h> |
| #include <osl/file.hxx> |
| #include <cppuhelper/weak.hxx> |
| #include <cppuhelper/queryinterface.hxx> |
| #include <comphelper/processfactory.hxx> |
| #include <rtl/uri.hxx> |
| #include <rtl/ustrbuf.hxx> |
| #include <libxslt/xslt.h> |
| #include <libxslt/transform.h> |
| #include <libxslt/xsltutils.h> |
| #include "db.hxx" |
| #include <com/sun/star/io/XActiveDataSink.hpp> |
| #include <com/sun/star/io/XInputStream.hpp> |
| #include <com/sun/star/io/XSeekable.hpp> |
| #include <com/sun/star/ucb/OpenCommandArgument2.hpp> |
| #include <com/sun/star/ucb/OpenMode.hpp> |
| #include <com/sun/star/ucb/XCommandProcessor.hpp> |
| #include <com/sun/star/ucb/XCommandEnvironment.hpp> |
| #include <com/sun/star/ucb/XContentIdentifier.hpp> |
| #include <com/sun/star/ucb/XContentProvider.hpp> |
| #include <com/sun/star/ucb/XContentIdentifierFactory.hpp> |
| #include <com/sun/star/container/XHierarchicalNameAccess.hpp> |
| #include <com/sun/star/beans/XPropertySet.hpp> |
| |
| #include "urlparameter.hxx" |
| #include "databases.hxx" |
| |
| namespace chelp { |
| |
| inline bool ascii_isDigit( sal_Unicode ch ) |
| { |
| return ((ch >= 0x0030) && (ch <= 0x0039)); |
| } |
| |
| inline bool ascii_isLetter( sal_Unicode ch ) |
| { |
| return ( ( (ch >= 0x0041) && (ch <= 0x005A) ) || |
| ( (ch >= 0x0061) && (ch <= 0x007A) ) ); |
| } |
| |
| inline bool isLetterOrDigit( sal_Unicode ch ) |
| { |
| return ascii_isLetter( ch ) || ascii_isDigit( ch ); |
| } |
| |
| } |
| |
| using namespace cppu; |
| using namespace com::sun::star::io; |
| using namespace com::sun::star::uno; |
| using namespace com::sun::star::lang; |
| using namespace com::sun::star::ucb; |
| using namespace com::sun::star::beans; |
| using namespace com::sun::star::container; |
| using namespace chelp; |
| |
| |
| URLParameter::URLParameter( const rtl::OUString& aURL, |
| Databases* pDatabases ) |
| throw( com::sun::star::ucb::IllegalIdentifierException ) |
| : m_pDatabases( pDatabases ), |
| m_aURL( aURL ) |
| { |
| init( false ); |
| parse(); |
| } |
| |
| |
| bool URLParameter::isErrorDocument() |
| { |
| bool bErrorDoc = false; |
| |
| if( isFile() ) |
| { |
| Reference< XHierarchicalNameAccess > xNA = |
| m_pDatabases->findJarFileForPath( get_jar(), get_language(), get_path() ); |
| bErrorDoc = !xNA.is(); |
| } |
| |
| return bErrorDoc; |
| } |
| |
| |
| rtl::OString URLParameter::getByName( const char* par ) |
| { |
| rtl::OUString val; |
| |
| if( strcmp( par,"Program" ) == 0 ) |
| val = get_program(); |
| else if( strcmp( par,"Database" ) == 0 ) |
| val = get_module(); |
| else if( strcmp( par,"DatabasePar" ) == 0 ) |
| val = get_dbpar(); |
| else if( strcmp( par,"Id" ) == 0 ) |
| val = get_id(); |
| else if( strcmp( par,"Path" ) == 0 ) |
| val = get_path(); |
| else if( strcmp( par,"Language" ) == 0 ) |
| val = get_language(); |
| else if( strcmp( par,"System" ) == 0 ) |
| val = get_system(); |
| else if( strcmp( par,"HelpPrefix" ) == 0 ) |
| val = get_prefix(); |
| |
| return rtl::OString( val.getStr(),val.getLength(),RTL_TEXTENCODING_UTF8 ); |
| } |
| |
| |
| rtl::OUString URLParameter::get_id() |
| { |
| if( m_aId.compareToAscii("start") == 0 ) |
| { // module is set |
| StaticModuleInformation* inf = |
| m_pDatabases->getStaticInformationForModule( get_module(), |
| get_language() ); |
| if( inf ) |
| m_aId = inf->get_id(); |
| |
| m_bStart = true; |
| } |
| |
| return m_aId; |
| } |
| |
| rtl::OUString URLParameter::get_tag() |
| { |
| if( isFile() ) |
| return get_the_tag(); |
| else |
| return m_aTag; |
| } |
| |
| |
| rtl::OUString URLParameter::get_title() |
| { |
| if( isFile() ) |
| return get_the_title(); |
| else if( m_aModule.compareToAscii("") != 0 ) |
| { |
| StaticModuleInformation* inf = |
| m_pDatabases->getStaticInformationForModule( get_module(), |
| get_language() ); |
| if( inf ) |
| m_aTitle = inf->get_title(); |
| } |
| else // This must be the root |
| m_aTitle = rtl::OUString::createFromAscii("root"); |
| |
| return m_aTitle; |
| } |
| |
| |
| rtl::OUString URLParameter::get_language() |
| { |
| if( m_aLanguage.getLength() == 0 ) |
| return m_aDefaultLanguage; |
| |
| return m_aLanguage; |
| } |
| |
| |
| rtl::OUString URLParameter::get_program() |
| { |
| if( ! m_aProgram.getLength() ) |
| { |
| StaticModuleInformation* inf = |
| m_pDatabases->getStaticInformationForModule( get_module(), |
| get_language() ); |
| if( inf ) |
| m_aProgram = inf->get_program(); |
| } |
| return m_aProgram; |
| } |
| |
| |
| void URLParameter::init( bool bDefaultLanguageIsInitialized ) |
| { |
| (void)bDefaultLanguageIsInitialized; |
| |
| m_bHelpDataFileRead = false; |
| m_bStart = false; |
| m_bUseDB = true; |
| m_nHitCount = 100; // The default maximum hitcount |
| } |
| |
| |
| rtl::OUString URLParameter::get_the_tag() |
| { |
| if(m_bUseDB) { |
| if( ! m_bHelpDataFileRead ) |
| readHelpDataFile(); |
| |
| m_bHelpDataFileRead = true; |
| |
| return m_aTag; |
| } |
| else |
| return rtl::OUString(); |
| } |
| |
| |
| |
| rtl::OUString URLParameter::get_the_path() |
| { |
| if(m_bUseDB) { |
| if( ! m_bHelpDataFileRead ) |
| readHelpDataFile(); |
| m_bHelpDataFileRead = true; |
| |
| return m_aPath; |
| } |
| else |
| return get_id(); |
| } |
| |
| |
| |
| rtl::OUString URLParameter::get_the_title() |
| { |
| if(m_bUseDB) { |
| if( ! m_bHelpDataFileRead ) |
| readHelpDataFile(); |
| m_bHelpDataFileRead = true; |
| |
| return m_aTitle; |
| } |
| else |
| return rtl::OUString(); |
| } |
| |
| |
| rtl::OUString URLParameter::get_the_jar() |
| { |
| if(m_bUseDB) { |
| if( ! m_bHelpDataFileRead ) |
| readHelpDataFile(); |
| m_bHelpDataFileRead = true; |
| |
| return m_aJar; |
| } |
| else |
| return get_module() + rtl::OUString::createFromAscii(".jar"); |
| } |
| |
| |
| |
| |
| void URLParameter::readHelpDataFile() |
| { |
| static rtl::OUString aQuestionMark( rtl::OUString::createFromAscii( "?" ) ); |
| |
| if( get_id().compareToAscii("") == 0 ) |
| return; |
| |
| rtl::OUString aModule = get_module(); |
| rtl::OUString aLanguage = get_language(); |
| |
| DataBaseIterator aDbIt( *m_pDatabases, aModule, aLanguage, false ); |
| bool bSuccess = false; |
| |
| int nSize = 0; |
| const sal_Char* pData = NULL; |
| |
| helpdatafileproxy::HDFData aHDFData; |
| rtl::OUString aExtensionPath; |
| rtl::OUString aExtensionRegistryPath; |
| while( true ) |
| { |
| helpdatafileproxy::Hdf* pHdf = aDbIt.nextHdf( &aExtensionPath, &aExtensionRegistryPath ); |
| if( !pHdf ) |
| break; |
| |
| rtl::OString keyStr( m_aId.getStr(),m_aId.getLength(),RTL_TEXTENCODING_UTF8 ); |
| |
| bSuccess = pHdf->getValueForKey( keyStr, aHDFData ); |
| if( bSuccess ) |
| { |
| nSize = aHDFData.getSize(); |
| pData = aHDFData.getData(); |
| break; |
| } |
| } |
| |
| if( bSuccess ) |
| { |
| DbtToStringConverter converter( pData, nSize ); |
| m_aTitle = converter.getTitle(); |
| m_pDatabases->replaceName( m_aTitle ); |
| m_aPath = converter.getFile(); |
| m_aJar = converter.getDatabase(); |
| if( aExtensionPath.getLength() > 0 ) |
| { |
| rtl::OUStringBuffer aExtendedJarStrBuf; |
| aExtendedJarStrBuf.append( aQuestionMark ); |
| aExtendedJarStrBuf.append( aExtensionPath ); |
| aExtendedJarStrBuf.append( aQuestionMark ); |
| aExtendedJarStrBuf.append( m_aJar ); |
| m_aJar = aExtendedJarStrBuf.makeStringAndClear(); |
| m_aExtensionRegistryPath = aExtensionRegistryPath; |
| } |
| m_aTag = converter.getHash(); |
| } |
| } |
| |
| |
| |
| // Class encapsulating the transformation of the XInputStream to XHTML |
| |
| |
| class InputStreamTransformer |
| : public OWeakObject, |
| public XInputStream, |
| public XSeekable |
| { |
| public: |
| |
| InputStreamTransformer( URLParameter* urlParam, |
| Databases* pDatatabases, |
| bool isRoot = false ); |
| |
| ~InputStreamTransformer(); |
| |
| virtual Any SAL_CALL queryInterface( const Type& rType ) throw( RuntimeException ); |
| virtual void SAL_CALL acquire( void ) throw(); |
| virtual void SAL_CALL release( void ) throw(); |
| |
| virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData,sal_Int32 nBytesToRead ) |
| throw( NotConnectedException, |
| BufferSizeExceededException, |
| IOException, |
| RuntimeException); |
| |
| virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData,sal_Int32 nMaxBytesToRead ) |
| throw( NotConnectedException, |
| BufferSizeExceededException, |
| IOException, |
| RuntimeException); |
| |
| virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) throw( NotConnectedException, |
| BufferSizeExceededException, |
| IOException, |
| RuntimeException ); |
| |
| virtual sal_Int32 SAL_CALL available( void ) throw( NotConnectedException, |
| IOException, |
| RuntimeException ); |
| |
| virtual void SAL_CALL closeInput( void ) throw( NotConnectedException, |
| IOException, |
| RuntimeException ); |
| |
| virtual void SAL_CALL seek( sal_Int64 location ) throw( IllegalArgumentException, |
| IOException, |
| RuntimeException ); |
| |
| virtual sal_Int64 SAL_CALL getPosition( void ) throw( IOException,RuntimeException ); |
| |
| virtual sal_Int64 SAL_CALL getLength( void ) throw( IOException,RuntimeException ); |
| |
| void addToBuffer( const char* buffer,int len ); |
| |
| sal_Int8* getData() const { return (sal_Int8*) buffer; } |
| |
| sal_Int32 getLen() const { return sal_Int32( len ); } |
| |
| private: |
| |
| osl::Mutex m_aMutex; |
| |
| int len,pos; |
| char *buffer; |
| }; |
| |
| |
| |
| void URLParameter::open( const Reference< XMultiServiceFactory >& rxSMgr, |
| const Command& aCommand, |
| sal_Int32 CommandId, |
| const Reference< XCommandEnvironment >& Environment, |
| const Reference< XOutputStream >& xDataSink ) |
| { |
| (void)rxSMgr; |
| (void)aCommand; |
| (void)CommandId; |
| (void)Environment; |
| |
| if( ! xDataSink.is() ) |
| return; |
| |
| if( isPicture() ) |
| { |
| Reference< XInputStream > xStream; |
| Reference< XHierarchicalNameAccess > xNA = |
| m_pDatabases->jarFile( rtl::OUString::createFromAscii( "picture.jar" ), |
| get_language() ); |
| |
| rtl::OUString path = get_path(); |
| if( xNA.is() ) |
| { |
| try |
| { |
| Any aEntry = xNA->getByHierarchicalName( path ); |
| Reference< XActiveDataSink > xSink; |
| if( ( aEntry >>= xSink ) && xSink.is() ) |
| xStream = xSink->getInputStream(); |
| } |
| catch ( NoSuchElementException & ) |
| { |
| } |
| } |
| if( xStream.is() ) |
| { |
| sal_Int32 ret; |
| Sequence< sal_Int8 > aSeq( 4096 ); |
| while( true ) |
| { |
| try |
| { |
| ret = xStream->readBytes( aSeq,4096 ); |
| xDataSink->writeBytes( aSeq ); |
| if( ret < 4096 ) |
| break; |
| } |
| catch( const Exception& ) |
| { |
| break; |
| } |
| } |
| } |
| } |
| else |
| { |
| // a standard document or else an active help text, plug in the new input stream |
| InputStreamTransformer* p = new InputStreamTransformer( this,m_pDatabases,isRoot() ); |
| try |
| { |
| xDataSink->writeBytes( Sequence< sal_Int8 >( p->getData(),p->getLen() ) ); |
| } |
| catch( const Exception& ) |
| { |
| } |
| delete p; |
| } |
| xDataSink->closeOutput(); |
| } |
| |
| |
| |
| void URLParameter::open( const Reference< XMultiServiceFactory >& rxSMgr, |
| const Command& aCommand, |
| sal_Int32 CommandId, |
| const Reference< XCommandEnvironment >& Environment, |
| const Reference< XActiveDataSink >& xDataSink ) |
| { |
| (void)rxSMgr; |
| (void)aCommand; |
| (void)CommandId; |
| (void)Environment; |
| |
| if( isPicture() ) |
| { |
| Reference< XInputStream > xStream; |
| Reference< XHierarchicalNameAccess > xNA = |
| m_pDatabases->jarFile( rtl::OUString::createFromAscii( "picture.jar" ), |
| get_language() ); |
| |
| rtl::OUString path = get_path(); |
| if( xNA.is() ) |
| { |
| try |
| { |
| Any aEntry = xNA->getByHierarchicalName( path ); |
| Reference< XActiveDataSink > xSink; |
| if( ( aEntry >>= xSink ) && xSink.is() ) |
| xStream = xSink->getInputStream(); |
| } |
| catch ( NoSuchElementException & ) |
| { |
| } |
| } |
| #ifdef WORKAROUND_98119 |
| xDataSink->setInputStream( turnToSeekable(xStream) ); |
| #else |
| xDataSink->setInputStream( xStream ); |
| #endif |
| } |
| else |
| // a standard document or else an active help text, plug in the new input stream |
| xDataSink->setInputStream( new InputStreamTransformer( this,m_pDatabases,isRoot() ) ); |
| } |
| |
| |
| // #include <stdio.h> |
| |
| void URLParameter::parse() throw( com::sun::star::ucb::IllegalIdentifierException ) |
| { |
| // fprintf(stdout,"url send to xmlhelp: %s\n",(rtl::OUStringToOString(m_aURL,RTL_TEXTENCODING_UTF8).getStr())); |
| m_aExpr = m_aURL; |
| |
| sal_Int32 lstIdx = m_aExpr.lastIndexOf( sal_Unicode( '#' ) ); |
| if( lstIdx != -1 ) |
| m_aExpr = m_aExpr.copy( 0,lstIdx ); |
| |
| if( ! scheme() || |
| ! name( module() ) || |
| ! query() || |
| ! m_aLanguage.getLength() || |
| ! m_aSystem.getLength() ) |
| throw com::sun::star::ucb::IllegalIdentifierException(); |
| } |
| |
| |
| bool URLParameter::scheme() |
| { |
| // Correct extension help links as sometimes the |
| // module is missing resulting in a misformed URL |
| if( m_aExpr.compareToAscii( "vnd.sun.star.help:///", 21 ) == 0 ) |
| { |
| sal_Int32 nLen = m_aExpr.getLength(); |
| rtl::OUString aLastStr = m_aExpr.copy( nLen - 6 ); |
| if( aLastStr.compareToAscii( "DbPAR=" ) == 0 ) |
| { |
| rtl::OUString aNewExpr = m_aExpr.copy( 0, 20 ); |
| rtl::OUString aSharedStr = rtl::OUString::createFromAscii( "shared" ); |
| aNewExpr += aSharedStr; |
| aNewExpr += m_aExpr.copy( 20 ); |
| aNewExpr += aSharedStr; |
| m_aExpr = aNewExpr; |
| } |
| } |
| |
| for( sal_Int32 nPrefixLen = 20 ; nPrefixLen >= 18 ; --nPrefixLen ) |
| { |
| if( m_aExpr.compareToAscii( "vnd.sun.star.help://", nPrefixLen ) == 0 ) |
| { |
| m_aExpr = m_aExpr.copy( nPrefixLen ); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| bool URLParameter::module() |
| { |
| sal_Int32 idx = 0,length = m_aExpr.getLength(); |
| |
| while( idx < length && isLetterOrDigit( (m_aExpr.getStr())[idx] ) ) |
| ++idx; |
| |
| if( idx != 0 ) |
| { |
| m_aModule = m_aExpr.copy( 0,idx ); |
| m_aExpr = m_aExpr.copy( idx ); |
| return true; |
| } |
| else |
| return false; |
| } |
| |
| |
| |
| bool URLParameter::name( bool modulePresent ) |
| { |
| // if modulepresent, a name may be present, but must not |
| |
| sal_Int32 length = m_aExpr.getLength(); |
| |
| if( length != 0 && (m_aExpr.getStr())[0] == sal_Unicode( '/' ) ) |
| { |
| sal_Int32 idx = 1; |
| while( idx < length && (m_aExpr.getStr())[idx] != '?' ) |
| // ( isLetterOrDigit( (m_aExpr.getStr())[idx] ) |
| // || (m_aExpr.getStr())[idx] == '/' |
| // || (m_aExpr.getStr())[idx] == '.' )) |
| ++idx; |
| |
| if( idx != 1 && ! modulePresent ) |
| return false; |
| else |
| { |
| m_aId = m_aExpr.copy( 1,idx-1 ); |
| m_aExpr = m_aExpr.copy( idx ); |
| } |
| } |
| |
| // fprintf(stdout,"id %s\n",(rtl::OUStringToOString(m_aId,RTL_TEXTENCODING_UTF8).getStr())); |
| return true; |
| } |
| |
| |
| bool URLParameter::query() |
| { |
| rtl::OUString query_; |
| |
| if( ! m_aExpr.getLength() ) |
| return true; |
| else if( (m_aExpr.getStr())[0] == sal_Unicode( '?' ) ) |
| query_ = m_aExpr.copy( 1 ).trim(); |
| else |
| return false; |
| |
| |
| bool ret = true; |
| sal_Int32 delimIdx,equalIdx; |
| rtl::OUString parameter,value; |
| |
| while( query_.getLength() != 0 ) |
| { |
| delimIdx = query_.indexOf( sal_Unicode( '&' ) ); |
| equalIdx = query_.indexOf( sal_Unicode( '=' ) ); |
| parameter = query_.copy( 0,equalIdx ).trim(); |
| if( delimIdx == -1 ) |
| { |
| value = query_.copy( equalIdx + 1 ).trim(); |
| query_ = rtl::OUString(); |
| } |
| else |
| { |
| value = query_.copy( equalIdx+1,delimIdx - equalIdx - 1 ).trim(); |
| query_ = query_.copy( delimIdx+1 ).trim(); |
| } |
| |
| if( parameter.compareToAscii( "Language" ) == 0 ) |
| m_aLanguage = value; |
| else if( parameter.compareToAscii( "Device" ) == 0 ) |
| m_aDevice = value; |
| else if( parameter.compareToAscii( "Program" ) == 0 ) |
| m_aProgram = value; |
| else if( parameter.compareToAscii( "Eid" ) == 0 ) |
| m_aEid = value; |
| else if( parameter.compareToAscii( "UseDB" ) == 0 ) |
| m_bUseDB = ! ( value.compareToAscii("no") == 0 ); |
| else if( parameter.compareToAscii( "DbPAR" ) == 0 ) |
| m_aDbPar = value; |
| else if( parameter.compareToAscii( "Query" ) == 0 ) |
| { |
| if( ! m_aQuery.getLength() ) |
| m_aQuery = value; |
| else |
| m_aQuery += ( rtl::OUString::createFromAscii( " " ) + value ); |
| } |
| else if( parameter.compareToAscii( "Scope" ) == 0 ) |
| m_aScope = value; |
| else if( parameter.compareToAscii( "System" ) == 0 ) |
| m_aSystem = value; |
| else if( parameter.compareToAscii( "HelpPrefix" ) == 0 ) |
| m_aPrefix = rtl::Uri::decode( |
| value, |
| rtl_UriDecodeWithCharset, |
| RTL_TEXTENCODING_UTF8 ); |
| else if( parameter.compareToAscii( "HitCount" ) == 0 ) |
| m_nHitCount = value.toInt32(); |
| else if( parameter.compareToAscii( "Active" ) == 0 ) |
| m_aActive = value; |
| else |
| ret = false; |
| } |
| |
| return ret; |
| } |
| |
| struct UserData { |
| |
| UserData( InputStreamTransformer* pTransformer, |
| URLParameter* pInitial, |
| Databases* pDatabases ) |
| : m_pTransformer( pTransformer ), |
| m_pDatabases( pDatabases ), |
| m_pInitial( pInitial ) |
| { |
| } |
| |
| InputStreamTransformer* m_pTransformer; |
| Databases* m_pDatabases; |
| URLParameter* m_pInitial; |
| }; |
| |
| UserData *ugblData = 0; |
| |
| extern "C" { |
| |
| static int |
| fileMatch(const char * URI) { |
| if ((URI != NULL) && !strncmp(URI, "file:/", 6)) |
| return 1; |
| return 0; |
| } |
| |
| static int |
| zipMatch(const char * URI) { |
| if ((URI != NULL) && !strncmp(URI, "vnd.sun.star.zip:/", 18)) |
| return 1; |
| return 0; |
| } |
| |
| static int |
| helpMatch(const char * URI) { |
| if ((URI != NULL) && !strncmp(URI, "vnd.sun.star.help:/", 19)) |
| return 1; |
| return 0; |
| } |
| |
| static void * |
| fileOpen(const char *URI) { |
| osl::File *pRet = new osl::File(rtl::OUString(URI, strlen(URI), RTL_TEXTENCODING_UTF8)); |
| pRet->open(OpenFlag_Read); |
| return pRet; |
| } |
| |
| static void * |
| zipOpen(const char * /*URI*/) { |
| rtl::OUString language,jar,path; |
| |
| if( ugblData->m_pInitial->get_eid().getLength() ) |
| return (void*)(new Reference< XHierarchicalNameAccess >); |
| else |
| { |
| jar = ugblData->m_pInitial->get_jar(); |
| language = ugblData->m_pInitial->get_language(); |
| path = ugblData->m_pInitial->get_path(); |
| } |
| |
| Reference< XHierarchicalNameAccess > xNA = |
| ugblData->m_pDatabases->findJarFileForPath( jar, language, path ); |
| |
| Reference< XInputStream > xInputStream; |
| |
| if( xNA.is() ) |
| { |
| try |
| { |
| Any aEntry = xNA->getByHierarchicalName( path ); |
| Reference< XActiveDataSink > xSink; |
| if( ( aEntry >>= xSink ) && xSink.is() ) |
| xInputStream = xSink->getInputStream(); |
| } |
| catch ( NoSuchElementException & ) |
| { |
| } |
| } |
| |
| if( xInputStream.is() ) |
| { |
| return new Reference<XInputStream>(xInputStream); |
| } |
| return 0; |
| } |
| |
| static void * |
| helpOpen(const char * URI) { |
| rtl::OUString language,jar,path; |
| |
| URLParameter urlpar( rtl::OUString::createFromAscii( URI ), |
| ugblData->m_pDatabases ); |
| |
| jar = urlpar.get_jar(); |
| language = urlpar.get_language(); |
| path = urlpar.get_path(); |
| |
| Reference< XHierarchicalNameAccess > xNA = |
| ugblData->m_pDatabases->findJarFileForPath( jar, language, path ); |
| |
| Reference< XInputStream > xInputStream; |
| |
| if( xNA.is() ) |
| { |
| try |
| { |
| Any aEntry = xNA->getByHierarchicalName( path ); |
| Reference< XActiveDataSink > xSink; |
| if( ( aEntry >>= xSink ) && xSink.is() ) |
| xInputStream = xSink->getInputStream(); |
| } |
| catch ( NoSuchElementException & ) |
| { |
| } |
| } |
| |
| if( xInputStream.is() ) |
| return new Reference<XInputStream>(xInputStream); |
| return 0; |
| } |
| |
| static int |
| helpRead(void * context, char * buffer, int len) { |
| Reference< XInputStream > *pRef = (Reference< XInputStream >*)context; |
| |
| Sequence< sal_Int8 > aSeq; |
| len = (*pRef)->readBytes( aSeq,len); |
| memcpy(buffer, aSeq.getConstArray(), len); |
| |
| return len; |
| } |
| |
| static int |
| zipRead(void * context, char * buffer, int len) { |
| if( ugblData->m_pInitial->get_eid().getLength() ) |
| { |
| ugblData->m_pDatabases->popupDocument( ugblData->m_pInitial,&buffer,&len); |
| return len; |
| } |
| else |
| return helpRead(context, buffer, len); |
| } |
| |
| static int |
| fileRead(void * context, char * buffer, int len) { |
| int nRead = 0; |
| osl::File *pFile = (osl::File*)context; |
| if (pFile) |
| { |
| sal_uInt64 uRead = 0; |
| if (osl::FileBase::E_None == pFile->read(buffer, len, uRead)) |
| nRead = static_cast<int>(uRead); |
| } |
| return nRead; |
| } |
| |
| static int |
| uriClose(void * context) { |
| Reference< XInputStream > *pRef = (Reference< XInputStream >*)context; |
| delete pRef; |
| return 0; |
| } |
| |
| static int |
| fileClose(void * context) { |
| osl::File *pFile = (osl::File*)context; |
| if (pFile) |
| { |
| pFile->close(); |
| delete pFile; |
| } |
| return 0; |
| } |
| |
| } // extern "C" |
| |
| /* |
| // For debugging only |
| extern "C" void StructuredXMLErrorFunction(void *userData, xmlErrorPtr error) |
| { |
| (void)userData; |
| (void)error; |
| |
| // Reset error handler |
| xmlSetStructuredErrorFunc( NULL, NULL ); |
| } |
| */ |
| |
| InputStreamTransformer::InputStreamTransformer( URLParameter* urlParam, |
| Databases* pDatabases, |
| bool isRoot ) |
| : len( 0 ), |
| pos( 0 ), |
| buffer( new char[1] ) // Initializing with one element to avoid gcc compiler warning |
| { |
| if( isRoot ) |
| { |
| delete[] buffer; |
| pDatabases->cascadingStylesheet( urlParam->get_language(), |
| &buffer, |
| &len ); |
| } |
| else if( urlParam->isActive() ) |
| { |
| delete[] buffer; |
| pDatabases->setActiveText( urlParam->get_module(), |
| urlParam->get_language(), |
| urlParam->get_id(), |
| &buffer, |
| &len ); |
| } |
| else |
| { |
| UserData userData( this,urlParam,pDatabases ); |
| |
| // Uses the implementation detail, that rtl::OString::getStr returns a zero terminated character-array |
| |
| const char* parameter[47]; |
| rtl::OString parString[46]; |
| int last = 0; |
| |
| parString[last++] = "Program"; |
| rtl::OString aPureProgramm( urlParam->getByName( "Program" ) ); |
| parString[last++] = rtl::OString('\'') + aPureProgramm + rtl::OString('\''); |
| parString[last++] = "Database"; |
| parString[last++] = rtl::OString('\'') + urlParam->getByName( "DatabasePar" ) + rtl::OString('\''); |
| parString[last++] = "Id"; |
| parString[last++] = rtl::OString('\'') + urlParam->getByName( "Id" ) + rtl::OString('\''); |
| parString[last++] = "Path"; |
| rtl::OString aPath( urlParam->getByName( "Path" ) ); |
| parString[last++] = rtl::OString('\'') + aPath + rtl::OString('\''); |
| |
| rtl::OString aPureLanguage = urlParam->getByName( "Language" ); |
| parString[last++] = "Language"; |
| parString[last++] = rtl::OString('\'') + aPureLanguage + rtl::OString('\''); |
| parString[last++] = "System"; |
| parString[last++] = rtl::OString('\'') + urlParam->getByName( "System" ) + rtl::OString('\''); |
| parString[last++] = "productname"; |
| parString[last++] = rtl::OString('\'') + rtl::OString( |
| pDatabases->getProductName().getStr(), |
| pDatabases->getProductName().getLength(), |
| RTL_TEXTENCODING_UTF8 ) + rtl::OString('\''); |
| parString[last++] = "productversion"; |
| parString[last++] = rtl::OString('\'') + |
| rtl::OString( pDatabases->getProductVersion().getStr(), |
| pDatabases->getProductVersion().getLength(), |
| RTL_TEXTENCODING_UTF8 ) + rtl::OString('\''); |
| |
| parString[last++] = "imgrepos"; |
| parString[last++] = rtl::OString('\'') + pDatabases->getImagesZipFileURL() + rtl::OString('\''); |
| parString[last++] = "hp"; |
| parString[last++] = rtl::OString('\'') + urlParam->getByName( "HelpPrefix" ) + rtl::OString('\''); |
| |
| if( parString[last-1].getLength() ) |
| { |
| parString[last++] = "sm"; |
| parString[last++] = "'vnd.sun.star.help%3A%2F%2F'"; |
| parString[last++] = "qm"; |
| parString[last++] = "'%3F'"; |
| parString[last++] = "es"; |
| parString[last++] = "'%3D'"; |
| parString[last++] = "am"; |
| parString[last++] = "'%26'"; |
| parString[last++] = "cl"; |
| parString[last++] = "'%3A'"; |
| parString[last++] = "sl"; |
| parString[last++] = "'%2F'"; |
| parString[last++] = "hm"; |
| parString[last++] = "'%23'"; |
| parString[last++] = "cs"; |
| parString[last++] = "'css'"; |
| |
| parString[last++] = "vendorname"; |
| parString[last++] = rtl::OString("''"); |
| parString[last++] = "vendorversion"; |
| parString[last++] = rtl::OString("''"); |
| parString[last++] = "vendorshort"; |
| parString[last++] = rtl::OString("''"); |
| } |
| |
| // Do we need to add extension path? |
| ::rtl::OUString aExtensionPath; |
| rtl::OUString aJar = urlParam->get_jar(); |
| |
| bool bAddExtensionPath = false; |
| rtl::OUString aExtensionRegistryPath; |
| sal_Int32 nQuestionMark1 = aJar.indexOf( sal_Unicode('?') ); |
| sal_Int32 nQuestionMark2 = aJar.lastIndexOf( sal_Unicode('?') ); |
| if( nQuestionMark1 != -1 && nQuestionMark2 != -1 && nQuestionMark1 != nQuestionMark2 ) |
| { |
| aExtensionPath = aJar.copy( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 ); |
| aExtensionRegistryPath = urlParam->get_ExtensionRegistryPath(); |
| bAddExtensionPath = true; |
| } |
| else |
| { |
| // Path not yet specified, search directly |
| Reference< XHierarchicalNameAccess > xNA = pDatabases->findJarFileForPath |
| ( aJar, urlParam->get_language(), urlParam->get_path(), &aExtensionPath, &aExtensionRegistryPath ); |
| if( xNA.is() && aExtensionPath.getLength() ) |
| bAddExtensionPath = true; |
| } |
| |
| if( bAddExtensionPath ) |
| { |
| Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); |
| Reference< XPropertySet > xProps( xFactory, UNO_QUERY ); |
| OSL_ASSERT( xProps.is() ); |
| Reference< XComponentContext > xContext; |
| if (xProps.is()) |
| { |
| xProps->getPropertyValue( |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext; |
| } |
| if( !xContext.is() ) |
| { |
| throw RuntimeException( |
| ::rtl::OUString::createFromAscii( "InputStreamTransformer::InputStreamTransformer(), no XComponentContext" ), |
| Reference< XInterface >() ); |
| } |
| |
| rtl::OUString aOUExpandedExtensionPath = Databases::expandURL( aExtensionRegistryPath, xContext ); |
| rtl::OString aExpandedExtensionPath = rtl::OUStringToOString( aOUExpandedExtensionPath, osl_getThreadTextEncoding() ); |
| |
| parString[last++] = "ExtensionPath"; |
| parString[last++] = rtl::OString('\'') + aExpandedExtensionPath + rtl::OString('\''); |
| |
| // ExtensionId |
| rtl::OString aPureExtensionId; |
| sal_Int32 iSlash = aPath.indexOf( '/' ); |
| if( iSlash != -1 ) |
| aPureExtensionId = aPath.copy( 0, iSlash ); |
| |
| parString[last++] = "ExtensionId"; |
| parString[last++] = rtl::OString('\'') + aPureExtensionId + rtl::OString('\''); |
| } |
| |
| for( int i = 0; i < last; ++i ) |
| parameter[i] = parString[i].getStr(); |
| parameter[last] = 0; |
| |
| rtl::OUString xslURL = pDatabases->getInstallPathAsURL(); |
| |
| rtl::OString xslURLascii( |
| xslURL.getStr(), |
| xslURL.getLength(), |
| RTL_TEXTENCODING_UTF8); |
| xslURLascii += "main_transform.xsl"; |
| |
| ugblData = &userData; |
| |
| xmlInitParser(); |
| xmlRegisterInputCallbacks(zipMatch, zipOpen, zipRead, uriClose); |
| xmlRegisterInputCallbacks(helpMatch, helpOpen, helpRead, uriClose); |
| xmlRegisterInputCallbacks(fileMatch, fileOpen, fileRead, fileClose); |
| //xmlSetStructuredErrorFunc( NULL, (xmlStructuredErrorFunc)StructuredXMLErrorFunction ); |
| |
| xsltStylesheetPtr cur = |
| xsltParseStylesheetFile((const xmlChar *)xslURLascii.getStr()); |
| |
| xmlDocPtr doc = xmlParseFile("vnd.sun.star.zip:/"); |
| |
| xmlDocPtr res = xsltApplyStylesheet(cur, doc, parameter); |
| if (res) |
| { |
| xmlChar *doc_txt_ptr=0; |
| int doc_txt_len; |
| xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, res, cur); |
| addToBuffer((const char*)doc_txt_ptr, doc_txt_len); |
| xmlFree(doc_txt_ptr); |
| } |
| xmlPopInputCallbacks(); //filePatch |
| xmlPopInputCallbacks(); //helpPatch |
| xmlPopInputCallbacks(); //zipMatch |
| xmlFreeDoc(res); |
| xmlFreeDoc(doc); |
| xsltFreeStylesheet(cur); |
| } |
| } |
| |
| |
| InputStreamTransformer::~InputStreamTransformer() |
| { |
| delete[] buffer; |
| } |
| |
| |
| Any SAL_CALL InputStreamTransformer::queryInterface( const Type& rType ) throw( RuntimeException ) |
| { |
| Any aRet = ::cppu::queryInterface( rType, |
| SAL_STATIC_CAST( XInputStream*,this ), |
| SAL_STATIC_CAST( XSeekable*,this ) ); |
| |
| return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); |
| } |
| |
| |
| |
| void SAL_CALL InputStreamTransformer::acquire( void ) throw() |
| { |
| OWeakObject::acquire(); |
| } |
| |
| |
| |
| void SAL_CALL InputStreamTransformer::release( void ) throw() |
| { |
| OWeakObject::release(); |
| } |
| |
| |
| |
| sal_Int32 SAL_CALL InputStreamTransformer::readBytes( Sequence< sal_Int8 >& aData,sal_Int32 nBytesToRead ) |
| throw( NotConnectedException, |
| BufferSizeExceededException, |
| IOException, |
| RuntimeException) |
| { |
| osl::MutexGuard aGuard( m_aMutex ); |
| |
| int curr,available_ = len-pos; |
| if( nBytesToRead <= available_ ) |
| curr = nBytesToRead; |
| else |
| curr = available_; |
| |
| if( 0 <= curr && aData.getLength() < curr ) |
| aData.realloc( curr ); |
| |
| for( int k = 0; k < curr; ++k ) |
| aData[k] = buffer[pos++]; |
| |
| return curr > 0 ? curr : 0; |
| } |
| |
| |
| sal_Int32 SAL_CALL InputStreamTransformer::readSomeBytes( Sequence< sal_Int8 >& aData,sal_Int32 nMaxBytesToRead ) |
| throw( NotConnectedException, |
| BufferSizeExceededException, |
| IOException, |
| RuntimeException) |
| { |
| return readBytes( aData,nMaxBytesToRead ); |
| } |
| |
| |
| |
| void SAL_CALL InputStreamTransformer::skipBytes( sal_Int32 nBytesToSkip ) throw( NotConnectedException, |
| BufferSizeExceededException, |
| IOException, |
| RuntimeException ) |
| { |
| osl::MutexGuard aGuard( m_aMutex ); |
| while( nBytesToSkip-- ) ++pos; |
| } |
| |
| |
| |
| sal_Int32 SAL_CALL InputStreamTransformer::available( void ) throw( NotConnectedException, |
| IOException, |
| RuntimeException ) |
| { |
| osl::MutexGuard aGuard( m_aMutex ); |
| return len-pos > 0 ? len - pos : 0 ; |
| } |
| |
| |
| |
| void SAL_CALL InputStreamTransformer::closeInput( void ) throw( NotConnectedException, |
| IOException, |
| RuntimeException ) |
| { |
| } |
| |
| |
| |
| void SAL_CALL InputStreamTransformer::seek( sal_Int64 location ) throw( IllegalArgumentException, |
| IOException, |
| RuntimeException ) |
| { |
| osl::MutexGuard aGuard( m_aMutex ); |
| if( location < 0 ) |
| throw IllegalArgumentException(); |
| else |
| pos = sal::static_int_cast<sal_Int32>( location ); |
| |
| if( pos > len ) |
| pos = len; |
| } |
| |
| |
| |
| sal_Int64 SAL_CALL InputStreamTransformer::getPosition( void ) throw( IOException, |
| RuntimeException ) |
| { |
| osl::MutexGuard aGuard( m_aMutex ); |
| return sal_Int64( pos ); |
| } |
| |
| |
| |
| sal_Int64 SAL_CALL InputStreamTransformer::getLength( void ) throw( IOException,RuntimeException ) |
| { |
| osl::MutexGuard aGuard( m_aMutex ); |
| |
| return len; |
| } |
| |
| |
| void InputStreamTransformer::addToBuffer( const char* buffer_,int len_ ) |
| { |
| osl::MutexGuard aGuard( m_aMutex ); |
| |
| char* tmp = buffer; |
| buffer = new char[ len+len_ ]; |
| rtl_copyMemory( (void*)(buffer),(void*)(tmp),sal_uInt32( len ) ); |
| rtl_copyMemory( (void*)(buffer+len),(void*)(buffer_),sal_uInt32( len_ ) ); |
| delete[] tmp; |
| len += len_; |
| } |