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_sdext.hxx" 26 27 #include "pdfiadaptor.hxx" 28 #include "filterdet.hxx" 29 #include "saxemitter.hxx" 30 #include "odfemitter.hxx" 31 #include "inc/wrapper.hxx" 32 #include "inc/contentsink.hxx" 33 #include "tree/pdfiprocessor.hxx" 34 35 #include <osl/file.h> 36 #include <osl/thread.h> 37 #include <osl/diagnose.h> 38 #include <cppuhelper/factory.hxx> 39 #include <cppuhelper/implementationentry.hxx> 40 #include <com/sun/star/lang/XMultiComponentFactory.hpp> 41 #include <com/sun/star/uno/RuntimeException.hpp> 42 #include <com/sun/star/io/XInputStream.hpp> 43 #include <com/sun/star/frame/XLoadable.hpp> 44 #include <com/sun/star/xml/sax/XDocumentHandler.hpp> 45 #include <com/sun/star/io/XSeekable.hpp> 46 47 48 #include <boost/shared_ptr.hpp> 49 50 using namespace com::sun::star; 51 52 53 namespace pdfi 54 { 55 56 PDFIHybridAdaptor::PDFIHybridAdaptor( const uno::Reference< uno::XComponentContext >& xContext ) : 57 PDFIHybridAdaptorBase( m_aMutex ), 58 m_xContext( xContext ), 59 m_xModel() 60 { 61 } 62 63 // XFilter 64 sal_Bool SAL_CALL PDFIHybridAdaptor::filter( const uno::Sequence< beans::PropertyValue >& rFilterData ) throw( uno::RuntimeException ) 65 { 66 sal_Bool bRet = sal_False; 67 if( m_xModel.is() ) 68 { 69 uno::Reference< io::XStream > xSubStream; 70 rtl::OUString aPwd; 71 const beans::PropertyValue* pAttribs = rFilterData.getConstArray(); 72 sal_Int32 nAttribs = rFilterData.getLength(); 73 sal_Int32 nPwPos = -1; 74 for( sal_Int32 i = 0; i < nAttribs; i++ ) 75 { 76 #if OSL_DEBUG_LEVEL > 1 77 rtl::OUString aVal( RTL_CONSTASCII_USTRINGPARAM( "<no string>" ) ); 78 pAttribs[i].Value >>= aVal; 79 OSL_TRACE( "filter: Attrib: %s = %s\n", 80 rtl::OUStringToOString( pAttribs[i].Name, RTL_TEXTENCODING_UTF8 ).getStr(), 81 rtl::OUStringToOString( aVal, RTL_TEXTENCODING_UTF8 ).getStr() ); 82 #endif 83 if( pAttribs[i].Name.equalsAscii( "EmbeddedSubstream" ) ) 84 pAttribs[i].Value >>= xSubStream; 85 else if( pAttribs[i].Name.equalsAscii( "Password" ) ) 86 { 87 nPwPos = i; 88 pAttribs[i].Value >>= aPwd; 89 } 90 } 91 bool bAddPwdProp = false; 92 if( ! xSubStream.is() ) 93 { 94 uno::Reference< io::XInputStream > xInput; 95 for( sal_Int32 i = 0; i < nAttribs; i++ ) 96 { 97 if( pAttribs[i].Name.equalsAscii( "InputStream" ) ) 98 { 99 pAttribs[i].Value >>= xInput; 100 break; 101 } 102 } 103 if( xInput.is() ) 104 { 105 // TODO(P2): extracting hybrid substream twice - once during detection, second time here 106 uno::Reference< io::XSeekable > xSeek( xInput, uno::UNO_QUERY ); 107 if( xSeek.is() ) 108 xSeek->seek( 0 ); 109 oslFileHandle aFile = NULL; 110 sal_uInt64 nWritten = 0; 111 rtl::OUString aURL; 112 if( osl_createTempFile( NULL, &aFile, &aURL.pData ) == osl_File_E_None ) 113 { 114 OSL_TRACE( "created temp file %s\n", rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() ); 115 const sal_Int32 nBufSize = 4096; 116 uno::Sequence<sal_Int8> aBuf(nBufSize); 117 // copy the bytes 118 sal_Int32 nBytes; 119 do 120 { 121 nBytes = xInput->readBytes( aBuf, nBufSize ); 122 if( nBytes > 0 ) 123 { 124 osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten ); 125 if( static_cast<sal_Int32>(nWritten) != nBytes ) 126 { 127 xInput.clear(); 128 break; 129 } 130 } 131 } while( nBytes == nBufSize ); 132 osl_closeFile( aFile ); 133 if( xInput.is() ) 134 { 135 rtl::OUString aEmbedMimetype; 136 rtl::OUString aOrgPwd( aPwd ); 137 xSubStream = getAdditionalStream( aURL, aEmbedMimetype, aPwd, m_xContext, rFilterData, true ); 138 if( aOrgPwd != aPwd ) 139 bAddPwdProp = true; 140 } 141 osl_removeFile( aURL.pData ); 142 } 143 else 144 xSubStream.clear(); 145 } 146 } 147 if( xSubStream.is() ) 148 { 149 uno::Sequence< uno::Any > aArgs( 2 ); 150 aArgs[0] <<= m_xModel; 151 aArgs[1] <<= xSubStream; 152 153 OSL_TRACE( "try to instantiate subfilter\n" ); 154 uno::Reference< document::XFilter > xSubFilter; 155 try { 156 xSubFilter = uno::Reference<document::XFilter>( 157 m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( 158 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.OwnSubFilter" ) ), 159 aArgs, 160 m_xContext ), 161 uno::UNO_QUERY ); 162 } 163 catch(uno::Exception& e) 164 { 165 (void)e; 166 OSL_TRACE( "subfilter exception: %s\n", 167 OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 168 } 169 170 OSL_TRACE( "subfilter: %p\n", xSubFilter.get() ); 171 if( xSubFilter.is() ) 172 { 173 if( bAddPwdProp ) 174 { 175 uno::Sequence<beans::PropertyValue> aFilterData( rFilterData ); 176 if( nPwPos == -1 ) 177 { 178 nPwPos = aFilterData.getLength(); 179 aFilterData.realloc( nPwPos+1 ); 180 aFilterData[nPwPos].Name = rtl::OUString( 181 RTL_CONSTASCII_USTRINGPARAM( "Password" ) ); 182 } 183 aFilterData[nPwPos].Value <<= aPwd; 184 bRet = xSubFilter->filter( aFilterData ); 185 } 186 else 187 bRet = xSubFilter->filter( rFilterData ); 188 } 189 } 190 #if OSL_DEBUG_LEVEL > 1 191 else 192 OSL_TRACE( "PDFIAdaptor::filter: no embedded substream set\n" ); 193 #endif 194 } 195 #if OSL_DEBUG_LEVEL > 1 196 else 197 OSL_TRACE( "PDFIAdaptor::filter: no model set\n" ); 198 #endif 199 200 return bRet; 201 } 202 203 void SAL_CALL PDFIHybridAdaptor::cancel() throw() 204 { 205 } 206 207 //XImporter 208 void SAL_CALL PDFIHybridAdaptor::setTargetDocument( const uno::Reference< lang::XComponent >& xDocument ) throw( lang::IllegalArgumentException ) 209 { 210 OSL_TRACE( "PDFIAdaptor::setTargetDocument\n" ); 211 m_xModel = uno::Reference< frame::XModel >( xDocument, uno::UNO_QUERY ); 212 if( xDocument.is() && ! m_xModel.is() ) 213 throw lang::IllegalArgumentException(); 214 } 215 216 //--------------------------------------------------------------------------------------- 217 218 PDFIRawAdaptor::PDFIRawAdaptor( const uno::Reference< uno::XComponentContext >& xContext ) : 219 PDFIAdaptorBase( m_aMutex ), 220 m_xContext( xContext ), 221 m_xModel(), 222 m_pVisitorFactory(), 223 m_bEnableToplevelText(false) 224 { 225 } 226 227 void PDFIRawAdaptor::setTreeVisitorFactory(const TreeVisitorFactorySharedPtr& rVisitorFactory) 228 { 229 m_pVisitorFactory = rVisitorFactory; 230 } 231 232 bool PDFIRawAdaptor::parse( const uno::Reference<io::XInputStream>& xInput, 233 const uno::Reference<task::XInteractionHandler>& xIHdl, 234 const rtl::OUString& rPwd, 235 const uno::Reference<task::XStatusIndicator>& xStatus, 236 const XmlEmitterSharedPtr& rEmitter, 237 const rtl::OUString& rURL ) 238 { 239 // container for metaformat 240 boost::shared_ptr<PDFIProcessor> pSink( 241 new PDFIProcessor(xStatus, m_xContext)); 242 243 // TEMP! TEMP! 244 if( m_bEnableToplevelText ) 245 pSink->enableToplevelText(); 246 247 bool bSuccess=false; 248 249 if( xInput.is() && (!rURL.getLength() || rURL.compareToAscii( "file:", 5 ) != 0) ) 250 bSuccess = xpdf_ImportFromStream( xInput, pSink, xIHdl, rPwd, m_xContext ); 251 else 252 bSuccess = xpdf_ImportFromFile( rURL, pSink, xIHdl, rPwd, m_xContext ); 253 254 if( bSuccess ) 255 pSink->emit(*rEmitter,*m_pVisitorFactory); 256 257 return bSuccess; 258 } 259 260 bool PDFIRawAdaptor::odfConvert( const rtl::OUString& rURL, 261 const uno::Reference<io::XOutputStream>& xOutput, 262 const uno::Reference<task::XStatusIndicator>& xStatus ) 263 { 264 XmlEmitterSharedPtr pEmitter = createOdfEmitter(xOutput); 265 const bool bSuccess = parse(uno::Reference<io::XInputStream>(), 266 uno::Reference<task::XInteractionHandler>(), 267 rtl::OUString(), 268 xStatus,pEmitter,rURL); 269 270 // tell input stream that it is no longer needed 271 xOutput->closeOutput(); 272 273 return bSuccess; 274 } 275 276 // XImportFilter 277 sal_Bool SAL_CALL PDFIRawAdaptor::importer( const uno::Sequence< beans::PropertyValue >& rSourceData, 278 const uno::Reference< xml::sax::XDocumentHandler >& rHdl, 279 const uno::Sequence< rtl::OUString >& /*rUserData*/ ) throw( uno::RuntimeException ) 280 { 281 // get the InputStream carrying the PDF content 282 uno::Reference< io::XInputStream > xInput; 283 uno::Reference< task::XStatusIndicator > xStatus; 284 uno::Reference< task::XInteractionHandler > xInteractionHandler; 285 rtl::OUString aURL; 286 rtl::OUString aPwd; 287 const beans::PropertyValue* pAttribs = rSourceData.getConstArray(); 288 sal_Int32 nAttribs = rSourceData.getLength(); 289 for( sal_Int32 i = 0; i < nAttribs; i++, pAttribs++ ) 290 { 291 OSL_TRACE("importer Attrib: %s\n", OUStringToOString( pAttribs->Name, RTL_TEXTENCODING_UTF8 ).getStr() ); 292 if( pAttribs->Name.equalsAscii( "InputStream" ) ) 293 pAttribs->Value >>= xInput; 294 else if( pAttribs->Name.equalsAscii( "URL" ) ) 295 pAttribs->Value >>= aURL; 296 else if( pAttribs->Name.equalsAscii( "StatusIndicator" ) ) 297 pAttribs->Value >>= xStatus; 298 else if( pAttribs->Name.equalsAscii( "InteractionHandler" ) ) 299 pAttribs->Value >>= xInteractionHandler; 300 else if( pAttribs->Name.equalsAscii( "Password" ) ) 301 pAttribs->Value >>= aPwd; 302 } 303 if( !xInput.is() ) 304 return sal_False; 305 306 XmlEmitterSharedPtr pEmitter = createSaxEmitter(rHdl); 307 const bool bSuccess = parse(xInput,xInteractionHandler, aPwd, xStatus,pEmitter,aURL); 308 309 // tell input stream that it is no longer needed 310 xInput->closeInput(); 311 xInput.clear(); 312 313 return bSuccess; 314 } 315 316 //XImporter 317 void SAL_CALL PDFIRawAdaptor::setTargetDocument( const uno::Reference< lang::XComponent >& xDocument ) throw( lang::IllegalArgumentException ) 318 { 319 OSL_TRACE( "PDFIAdaptor::setTargetDocument\n" ); 320 m_xModel = uno::Reference< frame::XModel >( xDocument, uno::UNO_QUERY ); 321 if( xDocument.is() && ! m_xModel.is() ) 322 throw lang::IllegalArgumentException(); 323 } 324 325 } 326