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