Coverage Report

Created: 2026-03-31 11:00

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