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