Coverage Report

Created: 2026-07-30 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/poppler/qt6/src/poppler-pdf-converter.cc
Line
Count
Source
1
/* poppler-pdf-converter.cc: qt interface to poppler
2
 * Copyright (C) 2008, Pino Toscano <pino@kde.org>
3
 * Copyright (C) 2008, 2009, 2020-2022, 2024, 2025, Albert Astals Cid <aacid@kde.org>
4
 * Copyright (C) 2020, Thorsten Behrens <Thorsten.Behrens@CIB.de>
5
 * Copyright (C) 2020, Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by Technische Universität Dresden
6
 * Copyright (C) 2021, Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>.
7
 * Copyright (C) 2021, Zachary Travis <ztravis@everlaw.com>
8
 * Copyright (C) 2021, Georgiy Sgibnev <georgiy@sgibnev.com>. Work sponsored by lab50.net.
9
 * Copyright (C) 2022, Martin <martinbts@gmx.net>
10
 * Copyright (C) 2022, Felix Jung <fxjung@posteo.de>
11
 * Copyright (C) 2024, 2026, g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk>
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2, or (at your option)
16
 * any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
26
 */
27
28
#include "poppler-converter.h"
29
#include "poppler-qt6.h"
30
31
#include "poppler-annotation-helper.h"
32
#include "poppler-annotation-private.h"
33
#include "poppler-private.h"
34
#include "poppler-converter-private.h"
35
#include "poppler-qiodeviceoutstream-private.h"
36
37
#include <QFile>
38
#include <QUuid>
39
40
#include "Form.h"
41
#include <ErrorCodes.h>
42
43
namespace Poppler {
44
45
class PDFConverterPrivate : public BaseConverterPrivate
46
{
47
public:
48
    PDFConverterPrivate();
49
    ~PDFConverterPrivate() override;
50
51
    PDFConverter::PDFOptions opts;
52
};
53
54
0
PDFConverterPrivate::PDFConverterPrivate() = default;
55
56
0
PDFConverterPrivate::~PDFConverterPrivate() = default;
57
58
0
PDFConverter::PDFConverter(DocumentData *document) : BaseConverter(*new PDFConverterPrivate())
59
0
{
60
0
    Q_D(PDFConverter);
61
0
    d->document = document;
62
0
}
63
64
0
PDFConverter::~PDFConverter() = default;
65
66
void PDFConverter::setPDFOptions(PDFConverter::PDFOptions options)
67
0
{
68
0
    Q_D(PDFConverter);
69
0
    d->opts = options;
70
0
}
71
72
PDFConverter::PDFOptions PDFConverter::pdfOptions() const
73
0
{
74
0
    Q_D(const PDFConverter);
75
0
    return d->opts;
76
0
}
77
78
bool PDFConverter::convert()
79
0
{
80
0
    Q_D(PDFConverter);
81
0
    d->lastError = NoError;
82
83
0
    if (d->document->locked) {
84
0
        d->lastError = FileLockedError;
85
0
        return false;
86
0
    }
87
88
0
    QIODevice *dev = d->openDevice();
89
0
    if (!dev) {
90
0
        d->lastError = OpenOutputError;
91
0
        return false;
92
0
    }
93
94
0
    bool deleteFile = false;
95
0
    if (auto *file = qobject_cast<QFile *>(dev)) {
96
0
        deleteFile = !file->exists();
97
0
    }
98
99
0
    int errorCode = errNone;
100
0
    QIODeviceOutStream stream(dev);
101
0
    if (d->opts & WithChanges) {
102
0
        errorCode = d->document->doc->saveAs(&stream);
103
0
    } else {
104
0
        errorCode = d->document->doc->saveWithoutChangesAs(&stream);
105
0
    }
106
0
    d->closeDevice();
107
0
    if (errorCode != errNone) {
108
0
        if (deleteFile) {
109
0
            qobject_cast<QFile *>(dev)->remove();
110
0
        }
111
0
        if (errorCode == errOpenFile) {
112
0
            d->lastError = OpenOutputError;
113
0
        } else {
114
0
            d->lastError = NotSupportedInputFileError;
115
0
        }
116
0
    }
117
118
0
    return (errorCode == errNone);
119
0
}
120
121
bool PDFConverter::sign(const NewSignatureData &data)
122
0
{
123
0
    Q_D(PDFConverter);
124
0
    d->lastError = NoError;
125
126
0
    if (d->document->locked) {
127
0
        d->lastError = FileLockedError;
128
0
        return false;
129
0
    }
130
131
0
    if (data.signatureText().isEmpty()) {
132
0
        qWarning() << "No signature text given";
133
0
        return false;
134
0
    }
135
136
0
    ::PDFDoc *doc = d->document->doc.get();
137
0
    ::Page *destPage = doc->getPage(data.page() + 1);
138
0
    std::unique_ptr<GooString> gSignatureText = std::unique_ptr<GooString>(QStringToUnicodeGooString(data.signatureText()));
139
0
    std::unique_ptr<GooString> gSignatureLeftText = std::unique_ptr<GooString>(QStringToUnicodeGooString(data.signatureLeftText()));
140
0
    const auto reason = std::unique_ptr<GooString>(data.reason().isEmpty() ? nullptr : QStringToUnicodeGooString(data.reason()));
141
0
    const auto location = std::unique_ptr<GooString>(data.location().isEmpty() ? nullptr : QStringToUnicodeGooString(data.location()));
142
0
    const auto ownerPwd = std::optional<GooString>(data.documentOwnerPassword().constData());
143
0
    const auto userPwd = std::optional<GooString>(data.documentUserPassword().constData());
144
0
    auto failure = doc->sign(d->outputFileName.toUtf8().constData(), data.certNickname().toUtf8().constData(), data.password().toUtf8().constData(), QStringToGooString(data.fieldPartialName()), data.page() + 1,
145
0
                             boundaryToPdfRectangle(destPage, data.boundingRectangle(), Annotation::FixedRotation), *gSignatureText, *gSignatureLeftText, data.fontSize(), data.leftFontSize(), convertQColor(data.fontColor()),
146
0
                             data.borderWidth(), convertQColor(data.borderColor()), convertQColor(data.backgroundColor()), reason.get(), location.get(), data.imagePath().toStdString(), ownerPwd, userPwd);
147
0
    if (failure) {
148
0
        d->lastSigningErrorDetails = fromPopplerCore(failure.value().message);
149
0
        d->lastSigningResult = GenericSigningError; // catch all
150
0
        switch (failure.value().type) {
151
0
        case CryptoSign::SigningError::GenericError:
152
0
            d->lastSigningResult = GenericSigningError;
153
0
            break;
154
0
        case CryptoSign::SigningError::InternalError:
155
0
            d->lastSigningResult = InternalError;
156
0
            break;
157
0
        case CryptoSign::SigningError::KeyMissing:
158
0
            d->lastSigningResult = KeyMissing;
159
0
            break;
160
0
        case CryptoSign::SigningError::UserCancelled:
161
0
            d->lastSigningResult = UserCancelled;
162
163
0
            break;
164
0
        case CryptoSign::SigningError::WriteFailed:
165
0
            d->lastSigningResult = WriteFailed;
166
0
            break;
167
0
        case CryptoSign::SigningError::BadPassphrase:
168
169
0
            d->lastSigningResult = BadPassphrase;
170
0
            break;
171
0
        }
172
0
        return false;
173
0
    }
174
0
    d->lastSigningErrorDetails = {};
175
0
    d->lastSigningResult = SigningSuccess;
176
0
    return true;
177
0
}
178
179
PDFConverter::SigningResult PDFConverter::lastSigningResult() const
180
0
{
181
0
    Q_D(const PDFConverter);
182
0
    return d->lastSigningResult;
183
0
}
184
185
Poppler::ErrorString PDFConverter::lastSigningErrorDetails() const
186
0
{
187
0
    Q_D(const PDFConverter);
188
0
    return d->lastSigningErrorDetails;
189
0
}
190
191
struct PDFConverter::NewSignatureData::NewSignatureDataPrivate
192
{
193
0
    NewSignatureDataPrivate() = default;
194
195
    QString certNickname;
196
    QString password;
197
    int page;
198
    QRectF boundingRectangle;
199
    QString signatureText;
200
    QString signatureLeftText;
201
    QString reason;
202
    QString location;
203
    double fontSize = 10.0;
204
    double leftFontSize = 20.0;
205
    QColor fontColor = Qt::red;
206
    QColor borderColor = Qt::red;
207
    double borderWidth = 1.5;
208
    QColor backgroundColor = QColor(240, 240, 240);
209
210
    QString partialName = QUuid::createUuid().toString();
211
212
    QByteArray documentOwnerPassword;
213
    QByteArray documentUserPassword;
214
215
    QString imagePath;
216
};
217
218
0
PDFConverter::NewSignatureData::NewSignatureData() : d(new NewSignatureDataPrivate()) { }
219
220
PDFConverter::NewSignatureData::~NewSignatureData()
221
0
{
222
0
    delete d;
223
0
}
224
225
QString PDFConverter::NewSignatureData::certNickname() const
226
0
{
227
0
    return d->certNickname;
228
0
}
229
230
void PDFConverter::NewSignatureData::setCertNickname(const QString &certNickname)
231
0
{
232
0
    d->certNickname = certNickname;
233
0
}
234
235
QString PDFConverter::NewSignatureData::password() const
236
0
{
237
0
    return d->password;
238
0
}
239
240
void PDFConverter::NewSignatureData::setPassword(const QString &password)
241
0
{
242
0
    d->password = password;
243
0
}
244
245
int PDFConverter::NewSignatureData::page() const
246
0
{
247
0
    return d->page;
248
0
}
249
250
void PDFConverter::NewSignatureData::setPage(int page)
251
0
{
252
0
    d->page = page;
253
0
}
254
255
QRectF PDFConverter::NewSignatureData::boundingRectangle() const
256
0
{
257
0
    return d->boundingRectangle;
258
0
}
259
260
void PDFConverter::NewSignatureData::setBoundingRectangle(const QRectF &rect)
261
0
{
262
0
    d->boundingRectangle = rect;
263
0
}
264
265
QString PDFConverter::NewSignatureData::signatureText() const
266
0
{
267
0
    return d->signatureText;
268
0
}
269
270
void PDFConverter::NewSignatureData::setSignatureText(const QString &text)
271
0
{
272
0
    d->signatureText = text;
273
0
}
274
275
QString PDFConverter::NewSignatureData::signatureLeftText() const
276
0
{
277
0
    return d->signatureLeftText;
278
0
}
279
280
void PDFConverter::NewSignatureData::setSignatureLeftText(const QString &text)
281
0
{
282
0
    d->signatureLeftText = text;
283
0
}
284
285
QString PDFConverter::NewSignatureData::reason() const
286
0
{
287
0
    return d->reason;
288
0
}
289
290
void PDFConverter::NewSignatureData::setReason(const QString &reason)
291
0
{
292
0
    d->reason = reason;
293
0
}
294
295
QString PDFConverter::NewSignatureData::location() const
296
0
{
297
0
    return d->location;
298
0
}
299
300
void PDFConverter::NewSignatureData::setLocation(const QString &location)
301
0
{
302
0
    d->location = location;
303
0
}
304
305
double PDFConverter::NewSignatureData::fontSize() const
306
0
{
307
0
    return d->fontSize;
308
0
}
309
310
void PDFConverter::NewSignatureData::setFontSize(double fontSize)
311
0
{
312
0
    d->fontSize = fontSize;
313
0
}
314
315
double PDFConverter::NewSignatureData::leftFontSize() const
316
0
{
317
0
    return d->leftFontSize;
318
0
}
319
320
void PDFConverter::NewSignatureData::setLeftFontSize(double fontSize)
321
0
{
322
0
    d->leftFontSize = fontSize;
323
0
}
324
325
QColor PDFConverter::NewSignatureData::fontColor() const
326
0
{
327
0
    return d->fontColor;
328
0
}
329
330
void PDFConverter::NewSignatureData::setFontColor(const QColor &color)
331
0
{
332
0
    d->fontColor = color;
333
0
}
334
335
QColor PDFConverter::NewSignatureData::borderColor() const
336
0
{
337
0
    return d->borderColor;
338
0
}
339
340
void PDFConverter::NewSignatureData::setBorderColor(const QColor &color)
341
0
{
342
0
    d->borderColor = color;
343
0
}
344
345
QColor PDFConverter::NewSignatureData::backgroundColor() const
346
0
{
347
0
    return d->backgroundColor;
348
0
}
349
350
double PDFConverter::NewSignatureData::borderWidth() const
351
0
{
352
0
    return d->borderWidth;
353
0
}
354
355
void PDFConverter::NewSignatureData::setBorderWidth(double width)
356
0
{
357
0
    d->borderWidth = width;
358
0
}
359
360
void PDFConverter::NewSignatureData::setBackgroundColor(const QColor &color)
361
0
{
362
0
    d->backgroundColor = color;
363
0
}
364
365
QString PDFConverter::NewSignatureData::fieldPartialName() const
366
0
{
367
0
    return d->partialName;
368
0
}
369
370
void PDFConverter::NewSignatureData::setFieldPartialName(const QString &name)
371
0
{
372
0
    d->partialName = name;
373
0
}
374
375
QByteArray PDFConverter::NewSignatureData::documentOwnerPassword() const
376
0
{
377
0
    return d->documentOwnerPassword;
378
0
}
379
380
void PDFConverter::NewSignatureData::setDocumentOwnerPassword(const QByteArray &password)
381
0
{
382
0
    d->documentOwnerPassword = password;
383
0
}
384
385
QByteArray PDFConverter::NewSignatureData::documentUserPassword() const
386
0
{
387
0
    return d->documentUserPassword;
388
0
}
389
390
void PDFConverter::NewSignatureData::setDocumentUserPassword(const QByteArray &password)
391
0
{
392
0
    d->documentUserPassword = password;
393
0
}
394
395
QString PDFConverter::NewSignatureData::imagePath() const
396
0
{
397
0
    return d->imagePath;
398
0
}
399
400
void PDFConverter::NewSignatureData::setImagePath(const QString &path)
401
0
{
402
0
    d->imagePath = path;
403
0
}
404
}