[poppler] 2 commits - qt5/src qt5/tests

Albert Astals Cid aacid at kemper.freedesktop.org
Tue Jan 10 17:01:18 UTC 2017


 qt5/src/poppler-form.cc     |  133 +++++++++++++++++++++++++++++++++++++++++++-
 qt5/src/poppler-form.h      |  108 +++++++++++++++++++++++++++++++++++
 qt5/src/poppler-page.cc     |    7 ++
 qt5/tests/poppler-forms.cpp |   47 +++++++++++++++
 4 files changed, 292 insertions(+), 3 deletions(-)

New commits:
commit 8bb90fc828a3400a2464a38f0ec9e592754197dd
Author: Albert Astals Cid <aacid at kde.org>
Date:   Tue Jan 10 17:20:18 2017 +0100

    Qt5: Minor api refinements to the new signature classes

diff --git a/qt5/src/poppler-form.cc b/qt5/src/poppler-form.cc
index 898e5c1..03839bf 100644
--- a/qt5/src/poppler-form.cc
+++ b/qt5/src/poppler-form.cc
@@ -1,6 +1,6 @@
 /* poppler-form.h: qt interface to poppler
  * Copyright (C) 2007-2008, 2011, Pino Toscano <pino at kde.org>
- * Copyright (C) 2008, 2011, 2012, 2015, 2016 Albert Astals Cid <aacid at kde.org>
+ * Copyright (C) 2008, 2011, 2012, 2015-2017 Albert Astals Cid <aacid at kde.org>
  * Copyright (C) 2011 Carlos Garcia Campos <carlosgc at gnome.org>
  * Copyright (C) 2012, Adam Reichold <adamreichold at myopera.com>
  * Copyright (C) 2016, Hanno Meyer-Thurow <h.mth at web.de>
@@ -438,34 +438,46 @@ SignatureValidationInfo::SignatureValidationInfo(SignatureValidationInfoPrivate*
 {
 }
 
+SignatureValidationInfo::SignatureValidationInfo(const SignatureValidationInfo &other)
+ : d_ptr( other.d_ptr )
+{
+}
+
 SignatureValidationInfo::~SignatureValidationInfo()
 {
 }
 
-const SignatureValidationInfo::SignatureStatus SignatureValidationInfo::signatureStatus() const
+SignatureValidationInfo::SignatureStatus SignatureValidationInfo::signatureStatus() const
 {
   Q_D(const SignatureValidationInfo);
   return d->signature_status;
 }
 
-const SignatureValidationInfo::CertificateStatus SignatureValidationInfo::certificateStatus() const
+SignatureValidationInfo::CertificateStatus SignatureValidationInfo::certificateStatus() const
 {
   Q_D(const SignatureValidationInfo);
   return d->certificate_status;
 }
 
-const QString SignatureValidationInfo::signerName() const
+QString SignatureValidationInfo::signerName() const
 {
   Q_D(const SignatureValidationInfo);
   return d->signer_name;
 }
 
-const time_t SignatureValidationInfo::signingTime() const
+time_t SignatureValidationInfo::signingTime() const
 {
   Q_D(const SignatureValidationInfo);
   return d->signing_time;
 }
 
+SignatureValidationInfo &SignatureValidationInfo::operator=(const SignatureValidationInfo &other)
+{
+  if ( this != &other )
+    d_ptr = other.d_ptr;
+
+  return *this;
+}
 
 FormFieldSignature::FormFieldSignature(DocumentData *doc, ::Page *p, ::FormWidgetSignature *w)
   : FormField(*new FormFieldData(doc, p, w))
@@ -481,13 +493,11 @@ FormField::FormType FormFieldSignature::type() const
   return FormField::FormSignature;
 }
 
-void FormFieldSignature::validate(ValidateOptions opt,
-  QScopedPointer<SignatureValidationInfo>& svi) const
+SignatureValidationInfo FormFieldSignature::validate(ValidateOptions opt) const
 {
   FormWidgetSignature* fws = static_cast<FormWidgetSignature*>(m_formData->fm);
-  SignatureInfo* si = fws->validateSignature(
-    opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation);
-  SignatureValidationInfoPrivate* priv(new SignatureValidationInfoPrivate);
+  SignatureInfo* si = fws->validateSignature(opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation);
+  SignatureValidationInfoPrivate* priv = new SignatureValidationInfoPrivate;
   switch (si->getSignatureValStatus()) {
     case SIGNATURE_VALID:
       priv->signature_status = SignatureValidationInfo::SignatureValid;
@@ -539,7 +549,7 @@ void FormFieldSignature::validate(ValidateOptions opt,
   priv->signer_name = si->getSignerName();
   priv->signing_time = si->getSigningTime();
 
-  svi.reset(new SignatureValidationInfo(priv));
+  return SignatureValidationInfo(priv);
 }
 
 }
diff --git a/qt5/src/poppler-form.h b/qt5/src/poppler-form.h
index b19f2f7..401d79c 100644
--- a/qt5/src/poppler-form.h
+++ b/qt5/src/poppler-form.h
@@ -1,6 +1,6 @@
 /* poppler-form.h: qt interface to poppler
  * Copyright (C) 2007-2008, Pino Toscano <pino at kde.org>
- * Copyright (C) 2008, 2011, 2016, Albert Astals Cid <aacid at kde.org>
+ * Copyright (C) 2008, 2011, 2016, 2017, Albert Astals Cid <aacid at kde.org>
  * Copyright (C) 2012, Adam Reichold <adamreichold at myopera.com>
  * Copyright (C) 2016, Hanno Meyer-Thurow <h.mth at web.de>
  *
@@ -24,7 +24,7 @@
 
 #include <QtCore/QRectF>
 #include <QtCore/QStringList>
-#include <QtCore/QScopedPointer>
+#include <QtCore/QSharedPointer>
 #include "poppler-export.h"
 
 class Page;
@@ -390,29 +390,30 @@ namespace Poppler {
 	/**
 	  The signature status of the signature.
 	 */
-	const SignatureStatus signatureStatus() const;
+	SignatureStatus signatureStatus() const;
 
 	/**
 	  The certificate status of the signature.
 	 */
-	const CertificateStatus certificateStatus() const;
+	CertificateStatus certificateStatus() const;
 
 	/**
 	  The signer name associated with the signature.
 	 */
-	const QString signerName() const;
+	QString signerName() const;
 
 	/**
 	  The signing time associated with the signature.
 	 */
-	const time_t signingTime() const;
+	time_t signingTime() const;
+
+	SignatureValidationInfo(const SignatureValidationInfo &other);
+	SignatureValidationInfo &operator=(const SignatureValidationInfo &other);
 
 	private:
-	Q_DISABLE_COPY(SignatureValidationInfo)
 	Q_DECLARE_PRIVATE(SignatureValidationInfo)
 
-	private:
-	QScopedPointer<SignatureValidationInfoPrivate> d_ptr;
+	QSharedPointer<SignatureValidationInfoPrivate> d_ptr;
     };
 
     /**
@@ -443,8 +444,7 @@ namespace Poppler {
 
 	  Reset signature validatation info of scoped instance.
 	 */
-	void validate(ValidateOptions opt,
-		QScopedPointer<SignatureValidationInfo>& svi) const;
+	SignatureValidationInfo validate(ValidateOptions opt) const;
 
 	private:
 	Q_DISABLE_COPY(FormFieldSignature)
diff --git a/qt5/tests/poppler-forms.cpp b/qt5/tests/poppler-forms.cpp
index a2e9167..7297557 100644
--- a/qt5/tests/poppler-forms.cpp
+++ b/qt5/tests/poppler-forms.cpp
@@ -186,25 +186,25 @@ int main( int argc, char **argv )
 
                     case Poppler::FormField::FormSignature: {
                         const Poppler::FormFieldSignature *signatureForm = static_cast<const Poppler::FormFieldSignature *>(form);
-                        QScopedPointer<Poppler::SignatureValidationInfo> svi;
-                        signatureForm->validate(Poppler::FormFieldSignature::ValidateVerifyCertificate, svi);
-                        std::cout << "\t\t\tSignatureStatus: " << svi->signatureStatus() << std::endl;
-                        std::cout << "\t\t\tCertificateStatus: " << svi->certificateStatus() << std::endl;
-                        if (svi->signerName().isEmpty() == false)
-                          std::cout << "\t\t\tSignerName: " << svi->signerName() << std::endl;
+                        const Poppler::SignatureValidationInfo svi = signatureForm->validate(Poppler::FormFieldSignature::ValidateVerifyCertificate);
+                        std::cout << "\t\t\tSignatureStatus: " << svi.signatureStatus() << std::endl;
+                        std::cout << "\t\t\tCertificateStatus: " << svi.certificateStatus() << std::endl;
+                        if (svi.signerName().isEmpty() == false)
+                          std::cout << "\t\t\tSignerName: " << svi.signerName() << std::endl;
                         else
                           std::cout << "\t\t\tSignerName: " << "(null)" << std::endl;
                         // http://doc.qt.io/qt-5/qdatetime.html#fromTime_t-1
                         // Requires Qt 5.2 -> configure.ac update
                         // QDateTime::fromTime_t(svi->signingTime(), Qt::UTC).toString();
                         QDateTime sviTime;
-                        sviTime.setTime_t(svi->signingTime());
+                        sviTime.setTime_t(svi.signingTime());
                         std::cout << "\t\t\tSigningTime: " << sviTime.toString() << std::endl;
                     }
                     break;
                 }
             }
             qDeleteAll(forms);
+            delete page;
         }
     }
     delete doc;
commit aa63debdaa6001ed68333b31cd06c2f9958fd8d2
Author: Hanno Meyer-Thurow <h.mth at web.de>
Date:   Tue Jan 10 16:28:14 2017 +0100

    Qt5: Implement digital signature support
    
    Bug #94378

diff --git a/qt5/src/poppler-form.cc b/qt5/src/poppler-form.cc
index 91f0f34..898e5c1 100644
--- a/qt5/src/poppler-form.cc
+++ b/qt5/src/poppler-form.cc
@@ -3,6 +3,7 @@
  * Copyright (C) 2008, 2011, 2012, 2015, 2016 Albert Astals Cid <aacid at kde.org>
  * Copyright (C) 2011 Carlos Garcia Campos <carlosgc at gnome.org>
  * Copyright (C) 2012, Adam Reichold <adamreichold at myopera.com>
+ * Copyright (C) 2016, Hanno Meyer-Thurow <h.mth at web.de>
  *
  * 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
@@ -26,6 +27,7 @@
 #include <Form.h>
 #include <Object.h>
 #include <Link.h>
+#include <SignatureInfo.h>
 
 #include "poppler-form.h"
 #include "poppler-page-private.h"
@@ -421,4 +423,123 @@ bool FormFieldChoice::canBeSpellChecked() const
   return !fwc->noSpellCheck();
 }
 
+
+struct SignatureValidationInfoPrivate {
+	SignatureValidationInfo::SignatureStatus signature_status;
+	SignatureValidationInfo::CertificateStatus certificate_status;
+
+	QString signer_name;
+	time_t signing_time;
+};
+
+
+SignatureValidationInfo::SignatureValidationInfo(SignatureValidationInfoPrivate* priv)
+  : d_ptr(priv)
+{
+}
+
+SignatureValidationInfo::~SignatureValidationInfo()
+{
+}
+
+const SignatureValidationInfo::SignatureStatus SignatureValidationInfo::signatureStatus() const
+{
+  Q_D(const SignatureValidationInfo);
+  return d->signature_status;
+}
+
+const SignatureValidationInfo::CertificateStatus SignatureValidationInfo::certificateStatus() const
+{
+  Q_D(const SignatureValidationInfo);
+  return d->certificate_status;
+}
+
+const QString SignatureValidationInfo::signerName() const
+{
+  Q_D(const SignatureValidationInfo);
+  return d->signer_name;
+}
+
+const time_t SignatureValidationInfo::signingTime() const
+{
+  Q_D(const SignatureValidationInfo);
+  return d->signing_time;
+}
+
+
+FormFieldSignature::FormFieldSignature(DocumentData *doc, ::Page *p, ::FormWidgetSignature *w)
+  : FormField(*new FormFieldData(doc, p, w))
+{
+}
+
+FormFieldSignature::~FormFieldSignature()
+{
+}
+
+FormField::FormType FormFieldSignature::type() const
+{
+  return FormField::FormSignature;
+}
+
+void FormFieldSignature::validate(ValidateOptions opt,
+  QScopedPointer<SignatureValidationInfo>& svi) const
+{
+  FormWidgetSignature* fws = static_cast<FormWidgetSignature*>(m_formData->fm);
+  SignatureInfo* si = fws->validateSignature(
+    opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation);
+  SignatureValidationInfoPrivate* priv(new SignatureValidationInfoPrivate);
+  switch (si->getSignatureValStatus()) {
+    case SIGNATURE_VALID:
+      priv->signature_status = SignatureValidationInfo::SignatureValid;
+      break;
+    case SIGNATURE_INVALID:
+      priv->signature_status = SignatureValidationInfo::SignatureInvalid;
+      break;
+    case SIGNATURE_DIGEST_MISMATCH:
+      priv->signature_status = SignatureValidationInfo::SignatureDigestMismatch;
+      break;
+    case SIGNATURE_DECODING_ERROR:
+      priv->signature_status = SignatureValidationInfo::SignatureDecodingError;
+      break;
+    default:
+    case SIGNATURE_GENERIC_ERROR:
+      priv->signature_status = SignatureValidationInfo::SignatureGenericError;
+      break;
+    case SIGNATURE_NOT_FOUND:
+      priv->signature_status = SignatureValidationInfo::SignatureNotFound;
+      break;
+    case SIGNATURE_NOT_VERIFIED:
+      priv->signature_status = SignatureValidationInfo::SignatureNotVerified;
+      break;
+  }
+  switch (si->getCertificateValStatus()) {
+    case CERTIFICATE_TRUSTED:
+      priv->certificate_status = SignatureValidationInfo::CertificateTrusted;
+      break;
+    case CERTIFICATE_UNTRUSTED_ISSUER:
+      priv->certificate_status = SignatureValidationInfo::CertificateUntrustedIssuer;
+      break;
+    case CERTIFICATE_UNKNOWN_ISSUER:
+      priv->certificate_status = SignatureValidationInfo::CertificateUnknownIssuer;
+      break;
+    case CERTIFICATE_REVOKED:
+      priv->certificate_status = SignatureValidationInfo::CertificateRevoked;
+      break;
+    case CERTIFICATE_EXPIRED:
+      priv->certificate_status = SignatureValidationInfo::CertificateExpired;
+      break;
+    default:
+    case CERTIFICATE_GENERIC_ERROR:
+      priv->certificate_status = SignatureValidationInfo::CertificateGenericError;
+      break;
+    case CERTIFICATE_NOT_VERIFIED:
+      priv->certificate_status = SignatureValidationInfo::CertificateNotVerified;
+      break;
+  }
+  priv->signer_name = si->getSignerName();
+  priv->signing_time = si->getSigningTime();
+
+  svi.reset(new SignatureValidationInfo(priv));
+}
+
 }
diff --git a/qt5/src/poppler-form.h b/qt5/src/poppler-form.h
index 6a94181..b19f2f7 100644
--- a/qt5/src/poppler-form.h
+++ b/qt5/src/poppler-form.h
@@ -2,6 +2,7 @@
  * Copyright (C) 2007-2008, Pino Toscano <pino at kde.org>
  * Copyright (C) 2008, 2011, 2016, Albert Astals Cid <aacid at kde.org>
  * Copyright (C) 2012, Adam Reichold <adamreichold at myopera.com>
+ * Copyright (C) 2016, Hanno Meyer-Thurow <h.mth at web.de>
  *
  * 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
@@ -23,6 +24,7 @@
 
 #include <QtCore/QRectF>
 #include <QtCore/QStringList>
+#include <QtCore/QScopedPointer>
 #include "poppler-export.h"
 
 class Page;
@@ -30,6 +32,7 @@ class FormWidget;
 class FormWidgetButton;
 class FormWidgetText;
 class FormWidgetChoice;
+class FormWidgetSignature;
 
 namespace Poppler {
 
@@ -344,6 +347,109 @@ namespace Poppler {
 	Q_DISABLE_COPY(FormFieldChoice)
     };
 
+    /**
+      A signature validation info helper class.
+
+      \since xy.z
+     */
+    class SignatureValidationInfoPrivate;
+    class POPPLER_QT5_EXPORT SignatureValidationInfo {
+    public:
+
+	/**
+	   The verfication result of the signature.
+	*/
+	enum SignatureStatus {
+	    SignatureValid,          ///< The signature is cryptographically valid.
+	    SignatureInvalid,        ///< The signature is cryptographically invalid.
+	    SignatureDigestMismatch, ///< The document content was changed after the signature was applied.
+	    SignatureDecodingError,  ///< The signature CMS/PKCS7 structure is malformed.
+	    SignatureGenericError,   ///< The signature could not be verified.
+	    SignatureNotFound,       ///< The requested signature is not present in the document.
+	    SignatureNotVerified     ///< The signature is not yet verified.
+	};
+
+	/**
+	   The verification result of the certificate.
+	*/
+	enum CertificateStatus {
+	    CertificateTrusted,         ///< The certificate is considered trusted.
+	    CertificateUntrustedIssuer, ///< The issuer of this certificate has been marked as untrusted by the user.
+	    CertificateUnknownIssuer,   ///< The certificate trust chain has not finished in a trusted root certificate.
+	    CertificateRevoked,         ///< The certificate was revoked by the issuing certificate authority.
+	    CertificateExpired,         ///< The signing time is outside the validity bounds of this certificate.
+	    CertificateGenericError,    ///< The certificate could not be verified.
+	    CertificateNotVerified      ///< The certificate is not yet verified.
+	};
+
+	/// \cond PRIVATE
+	SignatureValidationInfo(SignatureValidationInfoPrivate *priv);
+	/// \endcond
+	~SignatureValidationInfo();
+
+	/**
+	  The signature status of the signature.
+	 */
+	const SignatureStatus signatureStatus() const;
+
+	/**
+	  The certificate status of the signature.
+	 */
+	const CertificateStatus certificateStatus() const;
+
+	/**
+	  The signer name associated with the signature.
+	 */
+	const QString signerName() const;
+
+	/**
+	  The signing time associated with the signature.
+	 */
+	const time_t signingTime() const;
+
+	private:
+	Q_DISABLE_COPY(SignatureValidationInfo)
+	Q_DECLARE_PRIVATE(SignatureValidationInfo)
+
+	private:
+	QScopedPointer<SignatureValidationInfoPrivate> d_ptr;
+    };
+
+    /**
+      A form field that represents a signature.
+
+      \since xy.z
+     */
+    class POPPLER_QT5_EXPORT FormFieldSignature : public FormField {
+    public:
+
+	/**
+	   The validation options of this signature.
+	*/
+	enum ValidateOptions {
+	    ValidateVerifyCertificate = 1, ///< Validate the certificate.
+	    ValidateForceRevalidation = 2, ///< Force revalidation of the certificate.
+	};
+
+	/// \cond PRIVATE
+	FormFieldSignature(DocumentData *doc, ::Page *p, ::FormWidgetSignature *w);
+	/// \endcond
+	virtual ~FormFieldSignature();
+
+	virtual FormType type() const;
+
+	/**
+	  Validate the signature.
+
+	  Reset signature validatation info of scoped instance.
+	 */
+	void validate(ValidateOptions opt,
+		QScopedPointer<SignatureValidationInfo>& svi) const;
+
+	private:
+	Q_DISABLE_COPY(FormFieldSignature)
+	};
+
 }
 
 #endif
diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc
index 029716e..4e35a36 100644
--- a/qt5/src/poppler-page.cc
+++ b/qt5/src/poppler-page.cc
@@ -16,6 +16,7 @@
  * Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
  * Copyright (C) 2015 William Bader <williambader at hotmail.com>
  * Copyright (C) 2016 Arseniy Lartsev <arseniy at alumni.chalmers.se>
+ * Copyright (C) 2016, Hanno Meyer-Thurow <h.mth at web.de>
  *
  * 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
@@ -767,6 +768,12 @@ QList<FormField*> Page::formFields() const
       }
       break;
 
+      case formSignature:
+      {
+        ff = new FormFieldSignature(m_page->parentDoc, p, static_cast<FormWidgetSignature*>(fm));
+      }
+      break;
+
       default: ;
     }
 
diff --git a/qt5/tests/poppler-forms.cpp b/qt5/tests/poppler-forms.cpp
index 40b6cdd..a2e9167 100644
--- a/qt5/tests/poppler-forms.cpp
+++ b/qt5/tests/poppler-forms.cpp
@@ -1,4 +1,5 @@
 #include <QtCore/QCoreApplication>
+#include <QtCore/QDateTime>
 #include <QtCore/QDebug>
 
 #include <iostream>
@@ -46,6 +47,34 @@ std::ostream& operator<< (std::ostream &out, Poppler::FormFieldChoice::ChoiceTyp
     return out;
 }
 
+std::ostream& operator<< (std::ostream &out, Poppler::SignatureValidationInfo::SignatureStatus status)
+{
+    switch (status) {
+        case Poppler::SignatureValidationInfo::SignatureValid:          out << "Valid";          break;
+        case Poppler::SignatureValidationInfo::SignatureInvalid:        out << "Invalid";        break;
+        case Poppler::SignatureValidationInfo::SignatureDigestMismatch: out << "DigestMismatch"; break;
+        case Poppler::SignatureValidationInfo::SignatureDecodingError:  out << "DecodingError";  break;
+        case Poppler::SignatureValidationInfo::SignatureGenericError:   out << "GenericError";   break;
+        case Poppler::SignatureValidationInfo::SignatureNotFound:       out << "NotFound";       break;
+        case Poppler::SignatureValidationInfo::SignatureNotVerified:    out << "NotVerifiedYet"; break;
+    }
+    return out;
+}
+
+std::ostream& operator<< (std::ostream &out, Poppler::SignatureValidationInfo::CertificateStatus status)
+{
+    switch (status) {
+        case Poppler::SignatureValidationInfo::CertificateTrusted:         out << "Trusted";         break;
+        case Poppler::SignatureValidationInfo::CertificateUntrustedIssuer: out << "UntrustedIssuer"; break;
+        case Poppler::SignatureValidationInfo::CertificateUnknownIssuer:   out << "UnknownIssuer";   break;
+        case Poppler::SignatureValidationInfo::CertificateRevoked:         out << "Revoked";         break;
+        case Poppler::SignatureValidationInfo::CertificateExpired:         out << "Expired";         break;
+        case Poppler::SignatureValidationInfo::CertificateGenericError:    out << "GenericError";    break;
+        case Poppler::SignatureValidationInfo::CertificateNotVerified:     out << "NotVerifiedYet";  break;
+    }
+    return out;
+}
+
 std::ostream& operator<< (std::ostream &out, Qt::Alignment alignment)
 {
     switch (alignment) {
@@ -155,7 +184,23 @@ int main( int argc, char **argv )
                     }
                     break;
 
-                    case Poppler::FormField::FormSignature:
+                    case Poppler::FormField::FormSignature: {
+                        const Poppler::FormFieldSignature *signatureForm = static_cast<const Poppler::FormFieldSignature *>(form);
+                        QScopedPointer<Poppler::SignatureValidationInfo> svi;
+                        signatureForm->validate(Poppler::FormFieldSignature::ValidateVerifyCertificate, svi);
+                        std::cout << "\t\t\tSignatureStatus: " << svi->signatureStatus() << std::endl;
+                        std::cout << "\t\t\tCertificateStatus: " << svi->certificateStatus() << std::endl;
+                        if (svi->signerName().isEmpty() == false)
+                          std::cout << "\t\t\tSignerName: " << svi->signerName() << std::endl;
+                        else
+                          std::cout << "\t\t\tSignerName: " << "(null)" << std::endl;
+                        // http://doc.qt.io/qt-5/qdatetime.html#fromTime_t-1
+                        // Requires Qt 5.2 -> configure.ac update
+                        // QDateTime::fromTime_t(svi->signingTime(), Qt::UTC).toString();
+                        QDateTime sviTime;
+                        sviTime.setTime_t(svi->signingTime());
+                        std::cout << "\t\t\tSigningTime: " << sviTime.toString() << std::endl;
+                    }
                     break;
                 }
             }


More information about the poppler mailing list