| /************************************************************** |
| * |
| * 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_sdext.hxx" |
| |
| #include "pdfiadaptor.hxx" |
| #include "filterdet.hxx" |
| #include "saxemitter.hxx" |
| #include "odfemitter.hxx" |
| #include "inc/wrapper.hxx" |
| #include "inc/contentsink.hxx" |
| #include "tree/pdfiprocessor.hxx" |
| |
| #include <osl/file.h> |
| #include <osl/thread.h> |
| #include <osl/diagnose.h> |
| #include <cppuhelper/factory.hxx> |
| #include <cppuhelper/implementationentry.hxx> |
| #include <com/sun/star/lang/XMultiComponentFactory.hpp> |
| #include <com/sun/star/uno/RuntimeException.hpp> |
| #include <com/sun/star/io/XInputStream.hpp> |
| #include <com/sun/star/frame/XLoadable.hpp> |
| #include <com/sun/star/xml/sax/XDocumentHandler.hpp> |
| #include <com/sun/star/io/XSeekable.hpp> |
| |
| |
| #include <boost/shared_ptr.hpp> |
| |
| using namespace com::sun::star; |
| |
| |
| namespace pdfi |
| { |
| |
| PDFIHybridAdaptor::PDFIHybridAdaptor( const uno::Reference< uno::XComponentContext >& xContext ) : |
| PDFIHybridAdaptorBase( m_aMutex ), |
| m_xContext( xContext ), |
| m_xModel() |
| { |
| } |
| |
| // XFilter |
| sal_Bool SAL_CALL PDFIHybridAdaptor::filter( const uno::Sequence< beans::PropertyValue >& rFilterData ) throw( uno::RuntimeException ) |
| { |
| sal_Bool bRet = sal_False; |
| if( m_xModel.is() ) |
| { |
| uno::Reference< io::XStream > xSubStream; |
| rtl::OUString aPwd; |
| const beans::PropertyValue* pAttribs = rFilterData.getConstArray(); |
| sal_Int32 nAttribs = rFilterData.getLength(); |
| sal_Int32 nPwPos = -1; |
| for( sal_Int32 i = 0; i < nAttribs; i++ ) |
| { |
| #if OSL_DEBUG_LEVEL > 1 |
| rtl::OUString aVal( RTL_CONSTASCII_USTRINGPARAM( "<no string>" ) ); |
| pAttribs[i].Value >>= aVal; |
| OSL_TRACE( "filter: Attrib: %s = %s\n", |
| rtl::OUStringToOString( pAttribs[i].Name, RTL_TEXTENCODING_UTF8 ).getStr(), |
| rtl::OUStringToOString( aVal, RTL_TEXTENCODING_UTF8 ).getStr() ); |
| #endif |
| if( pAttribs[i].Name.equalsAscii( "EmbeddedSubstream" ) ) |
| pAttribs[i].Value >>= xSubStream; |
| else if( pAttribs[i].Name.equalsAscii( "Password" ) ) |
| { |
| nPwPos = i; |
| pAttribs[i].Value >>= aPwd; |
| } |
| } |
| bool bAddPwdProp = false; |
| if( ! xSubStream.is() ) |
| { |
| uno::Reference< io::XInputStream > xInput; |
| for( sal_Int32 i = 0; i < nAttribs; i++ ) |
| { |
| if( pAttribs[i].Name.equalsAscii( "InputStream" ) ) |
| { |
| pAttribs[i].Value >>= xInput; |
| break; |
| } |
| } |
| if( xInput.is() ) |
| { |
| // TODO(P2): extracting hybrid substream twice - once during detection, second time here |
| uno::Reference< io::XSeekable > xSeek( xInput, uno::UNO_QUERY ); |
| if( xSeek.is() ) |
| xSeek->seek( 0 ); |
| oslFileHandle aFile = NULL; |
| sal_uInt64 nWritten = 0; |
| rtl::OUString aURL; |
| if( osl_createTempFile( NULL, &aFile, &aURL.pData ) == osl_File_E_None ) |
| { |
| OSL_TRACE( "created temp file %s\n", rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() ); |
| const sal_Int32 nBufSize = 4096; |
| uno::Sequence<sal_Int8> aBuf(nBufSize); |
| // copy the bytes |
| sal_Int32 nBytes; |
| do |
| { |
| nBytes = xInput->readBytes( aBuf, nBufSize ); |
| if( nBytes > 0 ) |
| { |
| osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten ); |
| if( static_cast<sal_Int32>(nWritten) != nBytes ) |
| { |
| xInput.clear(); |
| break; |
| } |
| } |
| } while( nBytes == nBufSize ); |
| osl_closeFile( aFile ); |
| if( xInput.is() ) |
| { |
| rtl::OUString aEmbedMimetype; |
| rtl::OUString aOrgPwd( aPwd ); |
| xSubStream = getAdditionalStream( aURL, aEmbedMimetype, aPwd, m_xContext, rFilterData, true ); |
| if( aOrgPwd != aPwd ) |
| bAddPwdProp = true; |
| } |
| osl_removeFile( aURL.pData ); |
| } |
| else |
| xSubStream.clear(); |
| } |
| } |
| if( xSubStream.is() ) |
| { |
| uno::Sequence< uno::Any > aArgs( 2 ); |
| aArgs[0] <<= m_xModel; |
| aArgs[1] <<= xSubStream; |
| |
| OSL_TRACE( "try to instantiate subfilter\n" ); |
| uno::Reference< document::XFilter > xSubFilter; |
| try { |
| xSubFilter = uno::Reference<document::XFilter>( |
| m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( |
| rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.OwnSubFilter" ) ), |
| aArgs, |
| m_xContext ), |
| uno::UNO_QUERY ); |
| } |
| catch(uno::Exception& e) |
| { |
| (void)e; |
| OSL_TRACE( "subfilter exception: %s\n", |
| OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); |
| } |
| |
| OSL_TRACE( "subfilter: %p\n", xSubFilter.get() ); |
| if( xSubFilter.is() ) |
| { |
| if( bAddPwdProp ) |
| { |
| uno::Sequence<beans::PropertyValue> aFilterData( rFilterData ); |
| if( nPwPos == -1 ) |
| { |
| nPwPos = aFilterData.getLength(); |
| aFilterData.realloc( nPwPos+1 ); |
| aFilterData[nPwPos].Name = rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( "Password" ) ); |
| } |
| aFilterData[nPwPos].Value <<= aPwd; |
| bRet = xSubFilter->filter( aFilterData ); |
| } |
| else |
| bRet = xSubFilter->filter( rFilterData ); |
| } |
| } |
| #if OSL_DEBUG_LEVEL > 1 |
| else |
| OSL_TRACE( "PDFIAdaptor::filter: no embedded substream set\n" ); |
| #endif |
| } |
| #if OSL_DEBUG_LEVEL > 1 |
| else |
| OSL_TRACE( "PDFIAdaptor::filter: no model set\n" ); |
| #endif |
| |
| return bRet; |
| } |
| |
| void SAL_CALL PDFIHybridAdaptor::cancel() throw() |
| { |
| } |
| |
| //XImporter |
| void SAL_CALL PDFIHybridAdaptor::setTargetDocument( const uno::Reference< lang::XComponent >& xDocument ) throw( lang::IllegalArgumentException ) |
| { |
| OSL_TRACE( "PDFIAdaptor::setTargetDocument\n" ); |
| m_xModel = uno::Reference< frame::XModel >( xDocument, uno::UNO_QUERY ); |
| if( xDocument.is() && ! m_xModel.is() ) |
| throw lang::IllegalArgumentException(); |
| } |
| |
| //--------------------------------------------------------------------------------------- |
| |
| PDFIRawAdaptor::PDFIRawAdaptor( const uno::Reference< uno::XComponentContext >& xContext ) : |
| PDFIAdaptorBase( m_aMutex ), |
| m_xContext( xContext ), |
| m_xModel(), |
| m_pVisitorFactory(), |
| m_bEnableToplevelText(false) |
| { |
| } |
| |
| void PDFIRawAdaptor::setTreeVisitorFactory(const TreeVisitorFactorySharedPtr& rVisitorFactory) |
| { |
| m_pVisitorFactory = rVisitorFactory; |
| } |
| |
| bool PDFIRawAdaptor::parse( const uno::Reference<io::XInputStream>& xInput, |
| const uno::Reference<task::XInteractionHandler>& xIHdl, |
| const rtl::OUString& rPwd, |
| const uno::Reference<task::XStatusIndicator>& xStatus, |
| const XmlEmitterSharedPtr& rEmitter, |
| const rtl::OUString& rURL ) |
| { |
| // container for metaformat |
| boost::shared_ptr<PDFIProcessor> pSink( |
| new PDFIProcessor(xStatus, m_xContext)); |
| |
| // TEMP! TEMP! |
| if( m_bEnableToplevelText ) |
| pSink->enableToplevelText(); |
| |
| bool bSuccess=false; |
| |
| if( xInput.is() && (!rURL.getLength() || rURL.compareToAscii( "file:", 5 ) != 0) ) |
| bSuccess = xpdf_ImportFromStream( xInput, pSink, xIHdl, rPwd, m_xContext ); |
| else |
| bSuccess = xpdf_ImportFromFile( rURL, pSink, xIHdl, rPwd, m_xContext ); |
| |
| if( bSuccess ) |
| pSink->emit(*rEmitter,*m_pVisitorFactory); |
| |
| return bSuccess; |
| } |
| |
| bool PDFIRawAdaptor::odfConvert( const rtl::OUString& rURL, |
| const uno::Reference<io::XOutputStream>& xOutput, |
| const uno::Reference<task::XStatusIndicator>& xStatus ) |
| { |
| XmlEmitterSharedPtr pEmitter = createOdfEmitter(xOutput); |
| const bool bSuccess = parse(uno::Reference<io::XInputStream>(), |
| uno::Reference<task::XInteractionHandler>(), |
| rtl::OUString(), |
| xStatus,pEmitter,rURL); |
| |
| // tell input stream that it is no longer needed |
| xOutput->closeOutput(); |
| |
| return bSuccess; |
| } |
| |
| // XImportFilter |
| sal_Bool SAL_CALL PDFIRawAdaptor::importer( const uno::Sequence< beans::PropertyValue >& rSourceData, |
| const uno::Reference< xml::sax::XDocumentHandler >& rHdl, |
| const uno::Sequence< rtl::OUString >& /*rUserData*/ ) throw( uno::RuntimeException ) |
| { |
| // get the InputStream carrying the PDF content |
| uno::Reference< io::XInputStream > xInput; |
| uno::Reference< task::XStatusIndicator > xStatus; |
| uno::Reference< task::XInteractionHandler > xInteractionHandler; |
| rtl::OUString aURL; |
| rtl::OUString aPwd; |
| const beans::PropertyValue* pAttribs = rSourceData.getConstArray(); |
| sal_Int32 nAttribs = rSourceData.getLength(); |
| for( sal_Int32 i = 0; i < nAttribs; i++, pAttribs++ ) |
| { |
| OSL_TRACE("importer Attrib: %s\n", OUStringToOString( pAttribs->Name, RTL_TEXTENCODING_UTF8 ).getStr() ); |
| if( pAttribs->Name.equalsAscii( "InputStream" ) ) |
| pAttribs->Value >>= xInput; |
| else if( pAttribs->Name.equalsAscii( "URL" ) ) |
| pAttribs->Value >>= aURL; |
| else if( pAttribs->Name.equalsAscii( "StatusIndicator" ) ) |
| pAttribs->Value >>= xStatus; |
| else if( pAttribs->Name.equalsAscii( "InteractionHandler" ) ) |
| pAttribs->Value >>= xInteractionHandler; |
| else if( pAttribs->Name.equalsAscii( "Password" ) ) |
| pAttribs->Value >>= aPwd; |
| } |
| if( !xInput.is() ) |
| return sal_False; |
| |
| XmlEmitterSharedPtr pEmitter = createSaxEmitter(rHdl); |
| const bool bSuccess = parse(xInput,xInteractionHandler, aPwd, xStatus,pEmitter,aURL); |
| |
| // tell input stream that it is no longer needed |
| xInput->closeInput(); |
| xInput.clear(); |
| |
| return bSuccess; |
| } |
| |
| //XImporter |
| void SAL_CALL PDFIRawAdaptor::setTargetDocument( const uno::Reference< lang::XComponent >& xDocument ) throw( lang::IllegalArgumentException ) |
| { |
| OSL_TRACE( "PDFIAdaptor::setTargetDocument\n" ); |
| m_xModel = uno::Reference< frame::XModel >( xDocument, uno::UNO_QUERY ); |
| if( xDocument.is() && ! m_xModel.is() ) |
| throw lang::IllegalArgumentException(); |
| } |
| |
| } |