LibreOffice Module sdext (master)  1
pdfiadaptor.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include "pdfiadaptor.hxx"
22 #include "filterdet.hxx"
23 #include <saxemitter.hxx>
24 #include <odfemitter.hxx>
25 #include "inc/wrapper.hxx"
26 #include <pdfiprocessor.hxx>
27 
28 #include <osl/file.h>
29 #include <sal/log.hxx>
30 #include <rtl/ref.hxx>
31 
33 #include <com/sun/star/lang/IllegalArgumentException.hpp>
34 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
35 #include <com/sun/star/io/XSeekable.hpp>
36 #include <tools/diagnose_ex.h>
37 
38 #include <memory>
39 
40 using namespace com::sun::star;
41 
42 
43 namespace pdfi
44 {
45 
46 PDFIHybridAdaptor::PDFIHybridAdaptor( const uno::Reference< uno::XComponentContext >& xContext ) :
48  m_xContext( xContext ),
49  m_xModel()
50 {
51 }
52 
53 // XFilter
54 sal_Bool SAL_CALL PDFIHybridAdaptor::filter( const uno::Sequence< beans::PropertyValue >& rFilterData )
55 {
56  bool bRet = false;
57  if( m_xModel.is() )
58  {
59  uno::Reference< io::XStream > xSubStream;
60  OUString aPwd;
61  const beans::PropertyValue* pAttribs = rFilterData.getConstArray();
62  sal_Int32 nAttribs = rFilterData.getLength();
63  sal_Int32 nPwPos = -1;
64  for( sal_Int32 i = 0; i < nAttribs; i++ )
65  {
66  SAL_INFO("sdext.pdfimport", "filter: Attrib: " << pAttribs[i].Name
67  << " = " << (pAttribs[i].Value.has<OUString>()
68  ? pAttribs[i].Value.get<OUString>()
69  : OUString("<no string>"))
70  << "\n");
71  if ( pAttribs[i].Name == "EmbeddedSubstream" )
72  pAttribs[i].Value >>= xSubStream;
73  else if ( pAttribs[i].Name == "Password" )
74  {
75  nPwPos = i;
76  pAttribs[i].Value >>= aPwd;
77  }
78  }
79  bool bAddPwdProp = false;
80  if( ! xSubStream.is() )
81  {
82  uno::Reference< io::XInputStream > xInput;
83  auto pAttr = std::find_if(rFilterData.begin(), rFilterData.end(),
84  [](const beans::PropertyValue& rAttr) { return rAttr.Name == "InputStream"; });
85  if (pAttr != rFilterData.end())
86  pAttr->Value >>= xInput;
87  if( xInput.is() )
88  {
89  // TODO(P2): extracting hybrid substream twice - once during detection, second time here
90  uno::Reference< io::XSeekable > xSeek( xInput, uno::UNO_QUERY );
91  if( xSeek.is() )
92  xSeek->seek( 0 );
93  oslFileHandle aFile = nullptr;
94  sal_uInt64 nWritten = 0;
95  OUString aURL;
96  if( osl_createTempFile( nullptr, &aFile, &aURL.pData ) == osl_File_E_None )
97  {
98  SAL_INFO("sdext.pdfimport", "created temp file " << aURL);
99  const sal_Int32 nBufSize = 4096;
100  uno::Sequence<sal_Int8> aBuf(nBufSize);
101  // copy the bytes
102  sal_Int32 nBytes;
103  do
104  {
105  nBytes = xInput->readBytes( aBuf, nBufSize );
106  if( nBytes > 0 )
107  {
108  osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
109  if( static_cast<sal_Int32>(nWritten) != nBytes )
110  {
111  xInput.clear();
112  break;
113  }
114  }
115  } while( nBytes == nBufSize );
116  osl_closeFile( aFile );
117  if( xInput.is() )
118  {
119  OUString aEmbedMimetype;
120  OUString aOrgPwd( aPwd );
121  xSubStream = getAdditionalStream( aURL, aEmbedMimetype, aPwd, m_xContext, rFilterData, true );
122  if( aOrgPwd != aPwd )
123  bAddPwdProp = true;
124  }
125  osl_removeFile( aURL.pData );
126  }
127  else
128  xSubStream.clear();
129  }
130  }
131  if( xSubStream.is() )
132  {
133  uno::Sequence< uno::Any > aArgs( 2 );
134  aArgs[0] <<= m_xModel;
135  aArgs[1] <<= xSubStream;
136 
137  SAL_INFO("sdext.pdfimport", "try to instantiate subfilter" );
138  uno::Reference< document::XFilter > xSubFilter;
139  try {
140  xSubFilter.set(
141  m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
142  "com.sun.star.document.OwnSubFilter",
143  aArgs,
144  m_xContext ),
145  uno::UNO_QUERY );
146  }
147  catch(const uno::Exception&)
148  {
149  TOOLS_INFO_EXCEPTION("sdext.pdfimport", "subfilter");
150  }
151 
152  SAL_INFO("sdext.pdfimport", "subfilter: " << xSubFilter.get() );
153  if( xSubFilter.is() )
154  {
155  if( bAddPwdProp )
156  {
157  uno::Sequence<beans::PropertyValue> aFilterData( rFilterData );
158  if( nPwPos == -1 )
159  {
160  nPwPos = aFilterData.getLength();
161  aFilterData.realloc( nPwPos+1 );
162  aFilterData[nPwPos].Name = "Password";
163  }
164  aFilterData[nPwPos].Value <<= aPwd;
165  bRet = xSubFilter->filter( aFilterData );
166  }
167  else
168  bRet = xSubFilter->filter( rFilterData );
169  }
170  }
171  else
172  SAL_INFO("sdext.pdfimport", "PDFIAdaptor::filter: no embedded substream set" );
173  }
174  else
175  SAL_INFO("sdext.pdfimport", "PDFIAdaptor::filter: no model set" );
176 
177  return bRet;
178 }
179 
181 {
182 }
183 
184 //XImporter
185 void SAL_CALL PDFIHybridAdaptor::setTargetDocument( const uno::Reference< lang::XComponent >& xDocument )
186 {
187  SAL_INFO("sdext.pdfimport", "PDFIAdaptor::setTargetDocument" );
188  m_xModel.set( xDocument, uno::UNO_QUERY );
189  if( xDocument.is() && ! m_xModel.is() )
190  throw lang::IllegalArgumentException();
191 }
192 
194 {
195  return "org.libreoffice.comp.documents.HybridPDFImport";
196 }
197 
198 sal_Bool PDFIHybridAdaptor::supportsService(OUString const & ServiceName)
199 {
200  return cppu::supportsService(this, ServiceName);
201 }
202 
203 css::uno::Sequence<OUString> PDFIHybridAdaptor::getSupportedServiceNames()
204 {
205  return {"com.sun.star.document.ImportFilter"};
206 }
207 
208 PDFIRawAdaptor::PDFIRawAdaptor( OUString const & implementationName, const uno::Reference< uno::XComponentContext >& xContext ) :
210  m_implementationName(implementationName),
211  m_xContext( xContext ),
212  m_xModel(),
213  m_pVisitorFactory()
214 {
215 }
216 
218 {
219  m_pVisitorFactory = rVisitorFactory;
220 }
221 
222 bool PDFIRawAdaptor::parse( const uno::Reference<io::XInputStream>& xInput,
223  const uno::Reference<task::XInteractionHandler>& xIHdl,
224  const OUString& rPwd,
225  const uno::Reference<task::XStatusIndicator>& xStatus,
226  const XmlEmitterSharedPtr& rEmitter,
227  const OUString& rURL,
228  const OUString& rFilterOptions )
229 {
230  // container for metaformat
231  auto pSink = std::make_shared<PDFIProcessor>(xStatus, m_xContext);
232 
233  bool bSuccess=false;
234 
235  if( xInput.is() )
236  bSuccess = xpdf_ImportFromStream( xInput, pSink, xIHdl,
237  rPwd, m_xContext, rFilterOptions );
238  else
239  bSuccess = xpdf_ImportFromFile( rURL, pSink, xIHdl,
240  rPwd, m_xContext, rFilterOptions );
241 
242  if( bSuccess )
243  pSink->emit(*rEmitter,*m_pVisitorFactory);
244 
245  return bSuccess;
246 }
247 
248 bool PDFIRawAdaptor::odfConvert( const OUString& rURL,
249  const uno::Reference<io::XOutputStream>& xOutput,
250  const uno::Reference<task::XStatusIndicator>& xStatus )
251 {
252  XmlEmitterSharedPtr pEmitter = createOdfEmitter(xOutput);
253  const bool bSuccess = parse(uno::Reference<io::XInputStream>(),
254  uno::Reference<task::XInteractionHandler>(),
255  OUString(),
256  xStatus,pEmitter,rURL, "");
257 
258  // tell input stream that it is no longer needed
259  xOutput->closeOutput();
260 
261  return bSuccess;
262 }
263 
264 // XImportFilter
265 sal_Bool SAL_CALL PDFIRawAdaptor::importer( const uno::Sequence< beans::PropertyValue >& rSourceData,
266  const uno::Reference< xml::sax::XDocumentHandler >& rHdl,
267  const uno::Sequence< OUString >& /*rUserData*/ )
268 {
269  // get the InputStream carrying the PDF content
270  uno::Reference< io::XInputStream > xInput;
271  uno::Reference< task::XStatusIndicator > xStatus;
272  uno::Reference< task::XInteractionHandler > xInteractionHandler;
273  OUString aURL;
274  OUString aPwd;
275  OUString aFilterOptions;
276  for( const beans::PropertyValue& rAttrib : rSourceData )
277  {
278  SAL_INFO("sdext.pdfimport", "importer Attrib: " << rAttrib.Name );
279  if ( rAttrib.Name == "InputStream" )
280  rAttrib.Value >>= xInput;
281  else if ( rAttrib.Name == "URL" )
282  rAttrib.Value >>= aURL;
283  else if ( rAttrib.Name == "StatusIndicator" )
284  rAttrib.Value >>= xStatus;
285  else if ( rAttrib.Name == "InteractionHandler" )
286  rAttrib.Value >>= xInteractionHandler;
287  else if ( rAttrib.Name == "Password" )
288  rAttrib.Value >>= aPwd;
289  else if ( rAttrib.Name == "FilterOptions" )
290  rAttrib.Value >>= aFilterOptions;
291  }
292  if( !xInput.is() )
293  return false;
294 
295  XmlEmitterSharedPtr pEmitter = createSaxEmitter(rHdl);
296  const bool bSuccess = parse(xInput, xInteractionHandler,
297  aPwd, xStatus, pEmitter, aURL, aFilterOptions);
298 
299  // tell input stream that it is no longer needed
300  xInput->closeInput();
301  xInput.clear();
302 
303  return bSuccess;
304 }
305 
306 //XImporter
307 void SAL_CALL PDFIRawAdaptor::setTargetDocument( const uno::Reference< lang::XComponent >& xDocument )
308 {
309  SAL_INFO("sdext.pdfimport", "PDFIAdaptor::setTargetDocument" );
310  m_xModel.set( xDocument, uno::UNO_QUERY );
311  if( xDocument.is() && ! m_xModel.is() )
312  throw lang::IllegalArgumentException();
313 }
314 
316 {
317  return m_implementationName;
318 }
319 
320 sal_Bool PDFIRawAdaptor::supportsService(OUString const & ServiceName)
321 {
322  return cppu::supportsService(this, ServiceName);
323 }
324 
325 css::uno::Sequence<OUString> PDFIRawAdaptor::getSupportedServiceNames()
326 {
327  return {"com.sun.star.document.ImportFilter"};
328 }
329 
330 
331 
332 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
334  css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
335 {
336  rtl::Reference<pdfi::PDFIRawAdaptor> pAdaptor = new pdfi::PDFIRawAdaptor( "org.libreoffice.comp.documents.WriterPDFImport", context );
337  pAdaptor->setTreeVisitorFactory(pdfi::createWriterTreeVisitorFactory());
338  pAdaptor->acquire();
339  return static_cast<cppu::OWeakObject*>(pAdaptor.get());
340 }
341 
342 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
344  css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
345 {
346  rtl::Reference<pdfi::PDFIRawAdaptor> pAdaptor = new pdfi::PDFIRawAdaptor( "org.libreoffice.comp.documents.DrawPDFImport", context );
347  pAdaptor->setTreeVisitorFactory(pdfi::createDrawTreeVisitorFactory());
348  pAdaptor->acquire();
349  return static_cast<cppu::OWeakObject*>(pAdaptor.get());
350 }
351 
352 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
354  css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
355 {
356  rtl::Reference<pdfi::PDFIRawAdaptor> pAdaptor = new pdfi::PDFIRawAdaptor( "org.libreoffice.comp.documents.ImpressPDFImport", context );
357  pAdaptor->setTreeVisitorFactory(pdfi::createImpressTreeVisitorFactory());
358  pAdaptor->acquire();
359  return static_cast<cppu::OWeakObject*>(pAdaptor.get());
360 }
361 
362 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
364  css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
365 {
366  return cppu::acquire(new pdfi::PDFIHybridAdaptor( context ));
367 }
368 
369 }
370 
371 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
URL aURL
Reference< frame::XModel > m_xModel
css::uno::Reference< css::uno::XComponentContext > m_xContext
Definition: pdfiadaptor.hxx:53
virtual sal_Bool SAL_CALL importer(const css::uno::Sequence< css::beans::PropertyValue > &rSourceData, const css::uno::Reference< css::xml::sax::XDocumentHandler > &rHdl, const css::uno::Sequence< OUString > &rUserData) override
osl::Mutex m_aMutex
sal_Bool SAL_CALL supportsService(OUString const &ServiceName) override
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * sdext_PDFIRawAdaptor_Draw_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
::cppu::WeakComponentImplHelper< css::document::XFilter, css::document::XImporter, css::lang::XServiceInfo > PDFIHybridAdaptorBase
Definition: pdfiadaptor.hxx:46
std::shared_ptr< TreeVisitorFactory > TreeVisitorFactorySharedPtr
aBuf
OUString Name
css::uno::Reference< css::frame::XModel > m_xModel
Definition: pdfiadaptor.hxx:55
css::uno::Reference< css::uno::XComponentContext > m_xContext
Definition: pdfiadaptor.hxx:88
OUString SAL_CALL getImplementationName() override
Value
bool xpdf_ImportFromFile(const OUString &rURL, const ContentSinkSharedPtr &rSink, const css::uno::Reference< css::task::XInteractionHandler > &xIHdl, const OUString &rPwd, const css::uno::Reference< css::uno::XComponentContext > &xContext, const OUString &rFilterOptions)
uno::Reference< io::XStream > getAdditionalStream(const OUString &rInPDFFileURL, OUString &rOutMimetype, OUString &io_rPwd, const uno::Reference< uno::XComponentContext > &xContext, const uno::Sequence< beans::PropertyValue > &rFilterData, bool bMayUseUI)
Definition: filterdet.cxx:467
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
Adapts raw pdf import to XImportFilter interface.
Definition: pdfiadaptor.hxx:82
XmlEmitterSharedPtr createOdfEmitter(const css::uno::Reference< css::io::XOutputStream > &xOut)
bool parse(const css::uno::Reference< css::io::XInputStream > &xInput, const css::uno::Reference< css::task::XInteractionHandler > &xIHdl, const OUString &rPwd, const css::uno::Reference< css::task::XStatusIndicator > &xStatus, const XmlEmitterSharedPtr &rEmitter, const OUString &rURL, const OUString &rFilterOptions)
int i
std::shared_ptr< XmlEmitter > XmlEmitterSharedPtr
Definition: xmlemitter.hxx:48
PDFIRawAdaptor(OUString const &implementationName, const css::uno::Reference< css::uno::XComponentContext > &xContext)
TreeVisitorFactorySharedPtr createWriterTreeVisitorFactory()
OUString const m_implementationName
Definition: pdfiadaptor.hxx:86
unsigned char sal_Bool
TreeVisitorFactorySharedPtr createImpressTreeVisitorFactory()
XmlEmitterSharedPtr createSaxEmitter(const css::uno::Reference< css::xml::sax::XDocumentHandler > &xDocHdl)
css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * sdext_PDFIRawAdaptor_Writer_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
#define TOOLS_INFO_EXCEPTION(area, stream)
OUString SAL_CALL getImplementationName() override
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * sdext_PDFIRawAdaptor_Impress_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
TreeVisitorFactorySharedPtr m_pVisitorFactory
Definition: pdfiadaptor.hxx:91
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * sdext_PDFIHybridAdaptor_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
#define SAL_INFO(area, stream)
virtual void SAL_CALL setTargetDocument(const css::uno::Reference< css::lang::XComponent > &xDocument) override
::cppu::WeakComponentImplHelper< css::xml::XImportFilter, css::document::XImporter, css::lang::XServiceInfo > PDFIAdaptorBase
Definition: pdfiadaptor.hxx:78
void setTreeVisitorFactory(const TreeVisitorFactorySharedPtr &rVisitorFactory)
Set factory object used to create the tree visitors.
bool odfConvert(const OUString &rURL, const css::uno::Reference< css::io::XOutputStream > &xOutput, const css::uno::Reference< css::task::XStatusIndicator > &xStatus)
Export pdf document to ODG.
sal_Bool SAL_CALL supportsService(OUString const &ServiceName) override
virtual sal_Bool SAL_CALL filter(const css::uno::Sequence< css::beans::PropertyValue > &rFilterData) override
Definition: pdfiadaptor.cxx:54
css::uno::Reference< css::frame::XModel > m_xModel
Definition: pdfiadaptor.hxx:90
virtual void SAL_CALL cancel() override
TreeVisitorFactorySharedPtr createDrawTreeVisitorFactory()
virtual void SAL_CALL setTargetDocument(const css::uno::Reference< css::lang::XComponent > &xDocument) override
const uno::Reference< uno::XComponentContext > m_xContext
Definition: wrapper.cxx:149
bool xpdf_ImportFromStream(const css::uno::Reference< css::io::XInputStream > &xInput, const ContentSinkSharedPtr &rSink, const css::uno::Reference< css::task::XInteractionHandler > &xIHdl, const OUString &rPwd, const css::uno::Reference< css::uno::XComponentContext > &xContext, const OUString &rFilterOptions)