[poppler] poppler/Form.cc poppler/Form.h poppler/PDFDoc.cc poppler/PDFDoc.h poppler/UTF.cc poppler/UTF.h qt5/src qt5/tests qt6/src qt6/tests utils/pdfsig.cc

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Sep 16 10:04:48 UTC 2021


 poppler/Form.cc                    |   16 ++++++++++------
 poppler/Form.h                     |   12 +++++++-----
 poppler/PDFDoc.cc                  |    4 ++--
 poppler/PDFDoc.h                   |    4 +++-
 poppler/UTF.cc                     |   23 +++++++++++++++++++++++
 poppler/UTF.h                      |    7 +++++++
 qt5/src/poppler-pdf-converter.cc   |   28 ++++++++++++++++++++++++++--
 qt5/src/poppler-private.h          |    2 ++
 qt5/src/poppler-qt5.h              |   21 +++++++++++++++++++++
 qt5/tests/check_utf_conversion.cpp |    5 +++++
 qt6/src/poppler-pdf-converter.cc   |   30 +++++++++++++++++++++++++++---
 qt6/src/poppler-private.h          |    2 ++
 qt6/src/poppler-qt6.h              |   21 +++++++++++++++++++++
 qt6/tests/check_utf_conversion.cpp |    5 +++++
 utils/pdfsig.cc                    |    9 +++++----
 15 files changed, 166 insertions(+), 23 deletions(-)

New commits:
commit a03ec4540bb7cf5aa462b818c335965c4f7f1d2a
Author: Georgiy Sgibnev <georgiy at sgibnev.com>
Date:   Thu Sep 16 10:04:45 2021 +0000

    Correct encoding of signature's properties Reason & Location + Qt API

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 57441651..66b52860 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -571,7 +571,7 @@ static bool hashFileRange(FILE *f, SignatureHandler *handler, Goffset start, Gof
 }
 #endif
 
-bool FormWidgetSignature::signDocument(const char *saveFilename, const char *certNickname, const char *digestName, const char *password, const char *reason)
+bool FormWidgetSignature::signDocument(const char *saveFilename, const char *certNickname, const char *digestName, const char *password, const GooString *reason, const GooString *location)
 {
 #ifdef ENABLE_NSS3
     if (!certNickname) {
@@ -594,10 +594,9 @@ bool FormWidgetSignature::signDocument(const char *saveFilename, const char *cer
     signatureField->setCertificateInfo(certInfo);
     updateWidgetAppearance(); // add visible signing info to appearance
 
-    GooString gReason(reason ? reason : "");
     Object vObj(new Dict(xref));
     Ref vref = xref->addIndirectObject(&vObj);
-    if (!createSignature(vObj, vref, GooString(signerName), gReason, tmpSignature.get())) {
+    if (!createSignature(vObj, vref, GooString(signerName), tmpSignature.get(), reason, location)) {
         return false;
     }
 
@@ -780,7 +779,7 @@ bool FormWidgetSignature::updateSignature(FILE *f, Goffset sigStart, Goffset sig
     return true;
 }
 
-bool FormWidgetSignature::createSignature(Object &vObj, Ref vRef, const GooString &name, const GooString &reason, const GooString *signature)
+bool FormWidgetSignature::createSignature(Object &vObj, Ref vRef, const GooString &name, const GooString *signature, const GooString *reason, const GooString *location)
 {
     vObj.dictAdd("Type", Object(objName, "Sig"));
     vObj.dictAdd("Filter", Object(objName, "Adobe.PPKLite"));
@@ -788,8 +787,13 @@ bool FormWidgetSignature::createSignature(Object &vObj, Ref vRef, const GooStrin
     vObj.dictAdd("Name", Object(name.copy()));
     GooString *date = timeToDateString(nullptr);
     vObj.dictAdd("M", Object(date));
-    if (reason.getLength() > 0)
-        vObj.dictAdd("Reason", Object(reason.copy()));
+    if (reason && (reason->getLength() > 0)) {
+        vObj.dictAdd("Reason", Object(reason->copy()));
+    }
+    if (location && (location->getLength() > 0)) {
+        vObj.dictAdd("Location", Object(location->copy()));
+    }
+
     vObj.dictAdd("Contents", Object(objHexString, signature->copy()));
     Object bObj(new Array(xref));
     // reserve space in byte range for maximum number of bytes
diff --git a/poppler/Form.h b/poppler/Form.h
index 13ca1f5f..8e4239f7 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -24,6 +24,7 @@
 // Copyright 2020 Marek Kasik <mkasik at redhat.com>
 // Copyright 2020 Thorsten Behrens <Thorsten.Behrens at CIB.de>
 // Copyright 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
+// Copyright 2021 Georgiy Sgibnev <georgiy at sgibnev.com>. Work sponsored by lab50.net.
 //
 //========================================================================
 
@@ -301,13 +302,14 @@ public:
     // the elements of the list are of type Goffset
     std::vector<Goffset> getSignedRangeBounds() const;
 
-    // creates or replaces the dictionary name "V" in the signature dictionary and
+    // Creates or replaces the dictionary name "V" in the signature dictionary and
     // fills it with the fields of the signature; the field "Contents" is the signature
     // in PKCS#7 format, which is calculated over the byte range encompassing the whole
     // document except for the signature itself; this byte range is specified in the
-    // field "ByteRange" in the dictionary "V"
-    // return success
-    bool signDocument(const char *filename, const char *certNickname, const char *digestName, const char *password, const char *reason = nullptr);
+    // field "ByteRange" in the dictionary "V".
+    // Arguments reason and location are UTF-16 big endian strings with BOM. An empty string and nullptr are acceptable too.
+    // Returns success.
+    bool signDocument(const char *filename, const char *certNickname, const char *digestName, const char *password, const GooString *reason = nullptr, const GooString *location = nullptr);
 
     // checks the length encoding of the signature and returns the hex encoded signature
     // if the check passed (and the checked file size as output parameter in checkedFileSize)
@@ -317,7 +319,7 @@ public:
     const GooString *getSignature() const;
 
 private:
-    bool createSignature(Object &vObj, Ref vRef, const GooString &name, const GooString &reason, const GooString *signature);
+    bool createSignature(Object &vObj, Ref vRef, const GooString &name, const GooString *signature, const GooString *reason = nullptr, const GooString *location = nullptr);
     bool getObjectStartEnd(GooString *filename, int objNum, Goffset *objStart, Goffset *objEnd);
     bool updateOffsets(FILE *f, Goffset objStart, Goffset objEnd, Goffset *sigStart, Goffset *sigEnd, Goffset *fileSize);
 
diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index d7288bce..7316552b 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -2121,7 +2121,7 @@ bool PDFDoc::hasJavascript()
 }
 
 bool PDFDoc::sign(const char *saveFilename, const char *certNickname, const char *password, GooString *partialFieldName, int page, const PDFRectangle &rect, const GooString &signatureText, const GooString &signatureTextLeft,
-                  double fontSize, std::unique_ptr<AnnotColor> &&fontColor, double borderWidth, std::unique_ptr<AnnotColor> &&borderColor, std::unique_ptr<AnnotColor> &&backgroundColor)
+                  double fontSize, std::unique_ptr<AnnotColor> &&fontColor, double borderWidth, std::unique_ptr<AnnotColor> &&borderColor, std::unique_ptr<AnnotColor> &&backgroundColor, const GooString *reason, const GooString *location)
 {
     ::Page *destPage = getPage(page + 1);
 
@@ -2173,7 +2173,7 @@ bool PDFDoc::sign(const char *saveFilename, const char *certNickname, const char
 
     FormWidgetSignature *fws = dynamic_cast<FormWidgetSignature *>(formWidget);
     if (fws) {
-        const bool res = fws->signDocument(saveFilename, certNickname, "SHA256", password);
+        const bool res = fws->signDocument(saveFilename, certNickname, "SHA256", password, reason, location);
 
         // Now remove the signature stuff in case the user wants to continue editing stuff
         // So the document object is clean
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index cc223eb2..abf0ec55 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -329,8 +329,10 @@ public:
     // scans the PDF and returns whether it contains any javascript
     bool hasJavascript();
 
+    // Arguments signatureText and signatureTextLeft are UTF-16 big endian strings with BOM.
+    // Arguments reason and location are UTF-16 big endian strings with BOM. An empty string and nullptr are acceptable too.
     bool sign(const char *saveFilename, const char *certNickname, const char *password, GooString *partialFieldName, int page, const PDFRectangle &rect, const GooString &signatureText, const GooString &signatureTextLeft, double fontSize,
-              std::unique_ptr<AnnotColor> &&fontColor, double borderWidth, std::unique_ptr<AnnotColor> &&borderColor, std::unique_ptr<AnnotColor> &&backgroundColor);
+              std::unique_ptr<AnnotColor> &&fontColor, double borderWidth, std::unique_ptr<AnnotColor> &&borderColor, std::unique_ptr<AnnotColor> &&backgroundColor, const GooString *reason = nullptr, const GooString *location = nullptr);
 
 private:
     // insert referenced objects in XRef
diff --git a/poppler/UTF.cc b/poppler/UTF.cc
index e7daabd6..fadd833f 100644
--- a/poppler/UTF.cc
+++ b/poppler/UTF.cc
@@ -20,6 +20,7 @@
 // Copyright (C) 2016 Jason Crain <jason at aquaticape.us>
 // Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by the LiMux project of the city of Munich
 // Copyright (C) 2018, 2020 Nelson Benítez León <nbenitezl at gmail.com>
+// Copyright (C) 2021 Georgiy Sgibnev <georgiy at sgibnev.com>. Work sponsored by lab50.net.
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -34,6 +35,8 @@
 #include "UnicodeMapFuncs.h"
 #include <algorithm>
 
+#include <config.h>
+
 bool UnicodeIsValid(Unicode ucs4)
 {
     return (ucs4 < 0x110000) && ((ucs4 & 0xfffff800) != 0xd800) && (ucs4 < 0xfdd0 || ucs4 > 0xfdef) && ((ucs4 & 0xfffe) != 0xfffe);
@@ -354,6 +357,26 @@ uint16_t *utf8ToUtf16(const char *utf8, int *len)
     return utf16;
 }
 
+GooString *utf8ToUtf16WithBom(const GooString &utf8)
+{
+    GooString *result = new GooString();
+    if (utf8.toStr().empty()) {
+        return result;
+    }
+    int tmp_length; // Number of UTF-16 symbols.
+    char *tmp_str = (char *)utf8ToUtf16(utf8.c_str(), &tmp_length);
+#ifndef WORDS_BIGENDIAN
+    for (int i = 0; i < tmp_length; i++) {
+        std::swap(tmp_str[i * 2], tmp_str[i * 2 + 1]);
+    }
+#endif
+
+    result->prependUnicodeMarker();
+    result->append(tmp_str, tmp_length * 2);
+    gfree(tmp_str);
+    return result;
+}
+
 static const uint32_t UTF16_ACCEPT = 0;
 static const uint32_t UTF16_REJECT = -1;
 
diff --git a/poppler/UTF.h b/poppler/UTF.h
index 23f2db30..0a85a0e2 100644
--- a/poppler/UTF.h
+++ b/poppler/UTF.h
@@ -9,6 +9,7 @@
 // Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by the LiMux project of the city of Munich
 // Copyright (C) 2018 Nelson Benítez León <nbenitezl at gmail.com>
 // Copyright (C) 2019, 2020 Albert Astals Cid <aacid at kde.org>
+// Copyright (C) 2021 Georgiy Sgibnev <georgiy at sgibnev.com>. Work sponsored by lab50.net.
 //
 //========================================================================
 
@@ -71,6 +72,12 @@ int POPPLER_PRIVATE_EXPORT utf8ToUtf16(const char *utf8, uint16_t *utf16, int ma
 // Allocate utf16 string and convert utf8 into it.
 uint16_t POPPLER_PRIVATE_EXPORT *utf8ToUtf16(const char *utf8, int *len = nullptr);
 
+// Converts a UTF-8 string to a big endian UTF-16 string with BOM.
+// The caller owns the returned pointer.
+//  utf8 - UTF-8 string to convert. An empty string is acceptable.
+// Returns a big endian UTF-16 string with BOM or an empty string without BOM.
+GooString POPPLER_PRIVATE_EXPORT *utf8ToUtf16WithBom(const GooString &utf8);
+
 // Count number of UTF-8 bytes required to convert a UTF-16 string to
 // UTF-8 (excluding terminating NULL).
 int POPPLER_PRIVATE_EXPORT utf16CountUtf8Bytes(const uint16_t *utf16);
diff --git a/qt5/src/poppler-pdf-converter.cc b/qt5/src/poppler-pdf-converter.cc
index fe7d14cc..3dcb4c16 100644
--- a/qt5/src/poppler-pdf-converter.cc
+++ b/qt5/src/poppler-pdf-converter.cc
@@ -5,6 +5,7 @@
  * Copyright (C) 2020, Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
  * Copyright (C) 2021, Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>.
  * Copyright (C) 2021, Zachary Travis <ztravis at everlaw.com>
+ * Copyright (C) 2021, Georgiy Sgibnev <georgiy at sgibnev.com>. Work sponsored by lab50.net.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -131,10 +132,11 @@ bool PDFConverter::sign(const NewSignatureData &data)
     ::Page *destPage = doc->getPage(data.page() + 1);
     std::unique_ptr<GooString> gSignatureText = std::unique_ptr<GooString>(QStringToUnicodeGooString(data.signatureText()));
     std::unique_ptr<GooString> gSignatureLeftText = std::unique_ptr<GooString>(QStringToUnicodeGooString(data.signatureLeftText()));
-
+    const auto reason = std::unique_ptr<GooString>(data.reason().isEmpty() ? nullptr : QStringToUnicodeGooString(data.reason()));
+    const auto location = std::unique_ptr<GooString>(data.location().isEmpty() ? nullptr : QStringToUnicodeGooString(data.location()));
     return doc->sign(d->outputFileName.toUtf8().constData(), data.certNickname().toUtf8().constData(), data.password().toUtf8().constData(), QStringToGooString(data.fieldPartialName()), data.page(),
                      boundaryToPdfRectangle(destPage, data.boundingRectangle(), Annotation::FixedRotation), *gSignatureText, *gSignatureLeftText, data.fontSize(), convertQColor(data.fontColor()), data.borderWidth(),
-                     convertQColor(data.borderColor()), convertQColor(data.backgroundColor()));
+                     convertQColor(data.borderColor()), convertQColor(data.backgroundColor()), reason.get(), location.get());
 }
 
 struct PDFConverter::NewSignatureData::NewSignatureDataPrivate
@@ -147,6 +149,8 @@ struct PDFConverter::NewSignatureData::NewSignatureDataPrivate
     QRectF boundingRectangle;
     QString signatureText;
     QString signatureLeftText;
+    QString reason;
+    QString location;
     double fontSize = 10.0;
     double leftFontSize = 20.0;
     QColor fontColor = Qt::red;
@@ -224,6 +228,26 @@ void PDFConverter::NewSignatureData::setSignatureLeftText(const QString &text)
     d->signatureLeftText = text;
 }
 
+QString PDFConverter::NewSignatureData::reason() const
+{
+    return d->reason;
+}
+
+void PDFConverter::NewSignatureData::setReason(const QString &reason)
+{
+    d->reason = reason;
+}
+
+QString PDFConverter::NewSignatureData::location() const
+{
+    return d->location;
+}
+
+void PDFConverter::NewSignatureData::setLocation(const QString &location)
+{
+    d->location = location;
+}
+
 double PDFConverter::NewSignatureData::fontSize() const
 {
     return d->fontSize;
diff --git a/qt5/src/poppler-private.h b/qt5/src/poppler-private.h
index 30e1373f..248f01c4 100644
--- a/qt5/src/poppler-private.h
+++ b/qt5/src/poppler-private.h
@@ -76,6 +76,8 @@ POPPLER_QT5_EXPORT QString UnicodeParsedString(const GooString *s1);
 
 POPPLER_QT5_EXPORT QString UnicodeParsedString(const std::string &s1);
 
+// Returns a big endian UTF-16 string with BOM or an empty string without BOM.
+// The caller owns the returned pointer.
 POPPLER_QT5_EXPORT GooString *QStringToUnicodeGooString(const QString &s);
 
 POPPLER_QT5_EXPORT GooString *QStringToGooString(const QString &s);
diff --git a/qt5/src/poppler-qt5.h b/qt5/src/poppler-qt5.h
index adc97ca1..f307a26e 100644
--- a/qt5/src/poppler-qt5.h
+++ b/qt5/src/poppler-qt5.h
@@ -27,6 +27,7 @@
  * Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
  * Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>.
  * Copyright (C) 2021 Mahmoud Khalil <mahmoudkhalil11 at gmail.com>
+ * Copyright (C) 2021 Georgiy Sgibnev <georgiy at sgibnev.com>. Work sponsored by lab50.net.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -2222,6 +2223,26 @@ public:
         QString signatureLeftText() const;
         void setSignatureLeftText(const QString &text);
 
+        /**
+         * Signature's property Reason.
+         *
+         * Default: an empty string.
+         *
+         * \since 21.10
+         */
+        QString reason() const;
+        void setReason(const QString &reason);
+
+        /**
+         * Signature's property Location.
+         *
+         * Default: an empty string.
+         *
+         * \since 21.10
+         */
+        QString location() const;
+        void setLocation(const QString &location);
+
         /**
          * Default: 10
          */
diff --git a/qt5/tests/check_utf_conversion.cpp b/qt5/tests/check_utf_conversion.cpp
index 9acf4ab9..4df1ca51 100644
--- a/qt5/tests/check_utf_conversion.cpp
+++ b/qt5/tests/check_utf_conversion.cpp
@@ -99,6 +99,11 @@ void TestUTFConversion::testUTF()
     QVERIFY(compare(utf16String, s.utf16()));
     free(utf16String);
 
+    GooString gsUtf8(str);
+    std::unique_ptr<GooString> gsUtf16_a(utf8ToUtf16WithBom(gsUtf8));
+    std::unique_ptr<GooString> gsUtf16_b(Poppler::QStringToUnicodeGooString(s));
+    QCOMPARE(gsUtf16_a->cmp(gsUtf16_b.get()), 0);
+
     // UTF-16 to UTF-8
 
     len = utf16CountUtf8Bytes(s.utf16());
diff --git a/qt6/src/poppler-pdf-converter.cc b/qt6/src/poppler-pdf-converter.cc
index 8f5a19d3..c74ac2be 100644
--- a/qt6/src/poppler-pdf-converter.cc
+++ b/qt6/src/poppler-pdf-converter.cc
@@ -4,7 +4,8 @@
  * Copyright (C) 2020, Thorsten Behrens <Thorsten.Behrens at CIB.de>
  * Copyright (C) 2020, Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
  * Copyright (C) 2021, Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>.
- * * Copyright (C) 2021, Zachary Travis <ztravis at everlaw.com>
+ * Copyright (C) 2021, Zachary Travis <ztravis at everlaw.com>
+ * Copyright (C) 2021, Georgiy Sgibnev <georgiy at sgibnev.com>. Work sponsored by lab50.net.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -131,10 +132,11 @@ bool PDFConverter::sign(const NewSignatureData &data)
     ::Page *destPage = doc->getPage(data.page() + 1);
     std::unique_ptr<GooString> gSignatureText = std::unique_ptr<GooString>(QStringToUnicodeGooString(data.signatureText()));
     std::unique_ptr<GooString> gSignatureLeftText = std::unique_ptr<GooString>(QStringToUnicodeGooString(data.signatureLeftText()));
-
+    const auto reason = std::unique_ptr<GooString>(data.reason().isEmpty() ? nullptr : QStringToUnicodeGooString(data.reason()));
+    const auto location = std::unique_ptr<GooString>(data.location().isEmpty() ? nullptr : QStringToUnicodeGooString(data.location()));
     return doc->sign(d->outputFileName.toUtf8().constData(), data.certNickname().toUtf8().constData(), data.password().toUtf8().constData(), QStringToGooString(data.fieldPartialName()), data.page(),
                      boundaryToPdfRectangle(destPage, data.boundingRectangle(), Annotation::FixedRotation), *gSignatureText, *gSignatureLeftText, data.fontSize(), convertQColor(data.fontColor()), data.borderWidth(),
-                     convertQColor(data.borderColor()), convertQColor(data.backgroundColor()));
+                     convertQColor(data.borderColor()), convertQColor(data.backgroundColor()), reason.get(), location.get());
 }
 
 struct PDFConverter::NewSignatureData::NewSignatureDataPrivate
@@ -147,6 +149,8 @@ struct PDFConverter::NewSignatureData::NewSignatureDataPrivate
     QRectF boundingRectangle;
     QString signatureText;
     QString signatureLeftText;
+    QString reason;
+    QString location;
     double fontSize = 10.0;
     double leftFontSize = 20.0;
     QColor fontColor = Qt::red;
@@ -224,6 +228,26 @@ void PDFConverter::NewSignatureData::setSignatureLeftText(const QString &text)
     d->signatureLeftText = text;
 }
 
+QString PDFConverter::NewSignatureData::reason() const
+{
+    return d->reason;
+}
+
+void PDFConverter::NewSignatureData::setReason(const QString &reason)
+{
+    d->reason = reason;
+}
+
+QString PDFConverter::NewSignatureData::location() const
+{
+    return d->location;
+}
+
+void PDFConverter::NewSignatureData::setLocation(const QString &location)
+{
+    d->location = location;
+}
+
 double PDFConverter::NewSignatureData::fontSize() const
 {
     return d->fontSize;
diff --git a/qt6/src/poppler-private.h b/qt6/src/poppler-private.h
index ca69d676..3dc5bc82 100644
--- a/qt6/src/poppler-private.h
+++ b/qt6/src/poppler-private.h
@@ -77,6 +77,8 @@ POPPLER_QT6_EXPORT QString UnicodeParsedString(const std::string &s1);
 
 POPPLER_QT6_EXPORT GooString *QStringToUnicodeGooString(const QString &s);
 
+// Returns a big endian UTF-16 string with BOM or an empty string without BOM.
+// The caller owns the returned pointer.
 POPPLER_QT6_EXPORT GooString *QStringToGooString(const QString &s);
 
 GooString *QDateTimeToUnicodeGooString(const QDateTime &dt);
diff --git a/qt6/src/poppler-qt6.h b/qt6/src/poppler-qt6.h
index 73ae20e7..c59ffe4d 100644
--- a/qt6/src/poppler-qt6.h
+++ b/qt6/src/poppler-qt6.h
@@ -27,6 +27,7 @@
  * Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
  * Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>.
  * Copyright (C) 2021 Mahmoud Khalil <mahmoudkhalil11 at gmail.com>
+ * Copyright (C) 2021 Georgiy Sgibnev <georgiy at sgibnev.com>. Work sponsored by lab50.net.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -1998,6 +1999,26 @@ public:
         QString signatureLeftText() const;
         void setSignatureLeftText(const QString &text);
 
+        /**
+         * Signature's property Reason.
+         *
+         * Default: an empty string.
+         *
+         * \since 21.10
+         */
+        QString reason() const;
+        void setReason(const QString &reason);
+
+        /**
+         * Signature's property Location.
+         *
+         * Default: an empty string.
+         *
+         * \since 21.10
+         */
+        QString location() const;
+        void setLocation(const QString &location);
+
         /**
          * Default: 10
          */
diff --git a/qt6/tests/check_utf_conversion.cpp b/qt6/tests/check_utf_conversion.cpp
index af5a65b4..f3110922 100644
--- a/qt6/tests/check_utf_conversion.cpp
+++ b/qt6/tests/check_utf_conversion.cpp
@@ -97,6 +97,11 @@ void TestUTFConversion::testUTF()
     QVERIFY(compare(utf16String, s.utf16()));
     free(utf16String);
 
+    GooString gsUtf8(str);
+    std::unique_ptr<GooString> gsUtf16_a(utf8ToUtf16WithBom(gsUtf8));
+    std::unique_ptr<GooString> gsUtf16_b(Poppler::QStringToUnicodeGooString(s));
+    QCOMPARE(gsUtf16_a->cmp(gsUtf16_b.get()), 0);
+
     // UTF-16 to UTF-8
 
     len = utf16CountUtf8Bytes(s.utf16());
diff --git a/utils/pdfsig.cc b/utils/pdfsig.cc
index cfc0ab54..f4d63813 100644
--- a/utils/pdfsig.cc
+++ b/utils/pdfsig.cc
@@ -39,6 +39,7 @@
 #include "SignatureInfo.h"
 #include "Win32Console.h"
 #include "numberofcharacters.h"
+#include "UTF.h"
 #include <libgen.h>
 
 static const char *getReadableSigState(SignatureValidationStatus sig_vs)
@@ -132,7 +133,7 @@ static int signatureNumber = 0;
 static char certNickname[256] = "";
 static char password[256] = "";
 static char digestName[256] = "SHA256";
-static char reason[256] = "";
+static GooString reason;
 static bool listNicknames = false;
 
 static const ArgDesc argDesc[] = { { "-nssdir", argGooString, &nssDir, 0, "path to directory of libnss3 database" },
@@ -144,7 +145,7 @@ static const ArgDesc argDesc[] = { { "-nssdir", argGooString, &nssDir, 0, "path
                                    { "-nick", argString, &certNickname, 256, "use the certificate with the given nickname for signing" },
                                    { "-kpw", argString, &password, 256, "password for the signing key (might be missing if the key isn't password protected)" },
                                    { "-digest", argString, &digestName, 256, "name of the digest algorithm (default: SHA256)" },
-                                   { "-reason", argString, &reason, 256, "reason for signing (default: no reason given)" },
+                                   { "-reason", argGooString, &reason, 0, "reason for signing (default: no reason given)" },
                                    { "-list-nicks", argFlag, &listNicknames, 0, "list available nicknames in the NSS database" },
                                    { "-v", argFlag, &printVersion, 0, "print copyright and version info" },
                                    { "-h", argFlag, &printHelp, 0, "print usage information" },
@@ -263,13 +264,13 @@ int main(int argc, char *argv[])
         if (etsiCAdESdetached)
             ffs->setSignatureType(ETSI_CAdES_detached);
         const char *pw = (strlen(password) == 0) ? nullptr : password;
-        const char *rs = (strlen(reason) == 0) ? nullptr : reason;
+        const auto rs = std::unique_ptr<GooString>(reason.toStr().empty() ? nullptr : utf8ToUtf16WithBom(reason));
         if (ffs->getNumWidgets() != 1) {
             printf("Unexpected number of widgets for the signature: %d\n", ffs->getNumWidgets());
             return 2;
         }
         FormWidgetSignature *fws = static_cast<FormWidgetSignature *>(ffs->getWidget(0));
-        const bool success = fws->signDocument(argv[2], certNickname, digestName, pw, rs);
+        const bool success = fws->signDocument(argv[2], certNickname, digestName, pw, rs.get());
         return success ? 0 : 3;
     }
 


More information about the poppler mailing list