[poppler] poppler/PDFDoc.cc poppler/PDFDoc.h poppler/XRef.cc poppler/XRef.h qt5/demos qt5/src qt6/demos qt6/src

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri May 14 22:18:15 UTC 2021


 poppler/PDFDoc.cc           |   20 ++++++++++----------
 poppler/PDFDoc.h            |    8 ++++----
 poppler/XRef.cc             |    8 +++++++-
 poppler/XRef.h              |    5 ++++-
 qt5/demos/viewer.cpp        |   21 +++++++++++++++++++++
 qt5/demos/viewer.h          |    2 ++
 qt5/src/poppler-document.cc |   10 ++++++++++
 qt5/src/poppler-private.cc  |   13 +++++++++++++
 qt5/src/poppler-private.h   |   19 +++++++++++++++----
 qt5/src/poppler-qt5.h       |   17 +++++++++++++++++
 qt6/demos/viewer.cpp        |   21 +++++++++++++++++++++
 qt6/demos/viewer.h          |    2 ++
 qt6/src/poppler-document.cc |   10 ++++++++++
 qt6/src/poppler-private.cc  |   13 +++++++++++++
 qt6/src/poppler-private.h   |   19 +++++++++++++++----
 qt6/src/poppler-qt6.h       |   17 +++++++++++++++++
 16 files changed, 181 insertions(+), 24 deletions(-)

New commits:
commit 2254e62a7e2fe3a4144251e47c7578ce3b717bc9
Author: Mahmoud Khalil <mahmoudkhalil11 at gmail.com>
Date:   Wed Jan 27 21:14:57 2021 +0200

    Provides the `wasReconstructed` value to caller
    
    Modifies the Poppler backend library to call a callback method submitted
    by callers in case a XRef reconstruction occurs, as well as, providing
    an API for setting the callback from the qt5/qt6 frontend so that users
    be able to set callback and check whether it has already happened or
    not.
    
    FIXES #416

diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index ca440ca1..56b929be 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -136,7 +136,7 @@ PDFDoc::PDFDoc()
     init();
 }
 
-PDFDoc::PDFDoc(const GooString *fileNameA, const GooString *ownerPassword, const GooString *userPassword, void *guiDataA)
+PDFDoc::PDFDoc(const GooString *fileNameA, const GooString *ownerPassword, const GooString *userPassword, void *guiDataA, const std::function<void()> &xrefReconstructedCallback)
 {
 #ifdef _WIN32
     int n, i;
@@ -176,11 +176,11 @@ PDFDoc::PDFDoc(const GooString *fileNameA, const GooString *ownerPassword, const
     // create stream
     str = new FileStream(file, 0, false, file->size(), Object(objNull));
 
-    ok = setup(ownerPassword, userPassword);
+    ok = setup(ownerPassword, userPassword, xrefReconstructedCallback);
 }
 
 #ifdef _WIN32
-PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword, GooString *userPassword, void *guiDataA)
+PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword, GooString *userPassword, void *guiDataA, const std::function<void()> &xrefReconstructedCallback)
 {
     OSVERSIONINFO version;
     int i;
@@ -217,11 +217,11 @@ PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword, Go
     // create stream
     str = new FileStream(file, 0, false, file->size(), Object(objNull));
 
-    ok = setup(ownerPassword, userPassword);
+    ok = setup(ownerPassword, userPassword, xrefReconstructedCallback);
 }
 #endif
 
-PDFDoc::PDFDoc(BaseStream *strA, const GooString *ownerPassword, const GooString *userPassword, void *guiDataA)
+PDFDoc::PDFDoc(BaseStream *strA, const GooString *ownerPassword, const GooString *userPassword, void *guiDataA, const std::function<void()> &xrefReconstructedCallback)
 {
 #ifdef _WIN32
     int n, i;
@@ -246,10 +246,10 @@ PDFDoc::PDFDoc(BaseStream *strA, const GooString *ownerPassword, const GooString
 #endif
     }
     str = strA;
-    ok = setup(ownerPassword, userPassword);
+    ok = setup(ownerPassword, userPassword, xrefReconstructedCallback);
 }
 
-bool PDFDoc::setup(const GooString *ownerPassword, const GooString *userPassword)
+bool PDFDoc::setup(const GooString *ownerPassword, const GooString *userPassword, const std::function<void()> &xrefReconstructedCallback)
 {
     pdfdocLocker();
 
@@ -278,12 +278,12 @@ bool PDFDoc::setup(const GooString *ownerPassword, const GooString *userPassword
     bool wasReconstructed = false;
 
     // read xref table
-    xref = new XRef(str, getStartXRef(), getMainXRefEntriesOffset(), &wasReconstructed);
+    xref = new XRef(str, getStartXRef(), getMainXRefEntriesOffset(), &wasReconstructed, false, xrefReconstructedCallback);
     if (!xref->isOk()) {
         if (wasReconstructed) {
             delete xref;
             startXRefPos = -1;
-            xref = new XRef(str, getStartXRef(true), getMainXRefEntriesOffset(true), &wasReconstructed);
+            xref = new XRef(str, getStartXRef(true), getMainXRefEntriesOffset(true), &wasReconstructed, false, xrefReconstructedCallback);
         }
         if (!xref->isOk()) {
             error(errSyntaxError, -1, "Couldn't read xref table");
@@ -305,7 +305,7 @@ bool PDFDoc::setup(const GooString *ownerPassword, const GooString *userPassword
             // try one more time to construct the Catalog, maybe the problem is damaged XRef
             delete catalog;
             delete xref;
-            xref = new XRef(str, 0, 0, nullptr, true);
+            xref = new XRef(str, 0, 0, nullptr, true, xrefReconstructedCallback);
             catalog = new Catalog(this);
         }
 
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index a9ce2bd3..2cd4b35d 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -121,13 +121,13 @@ enum PDFSubtypeConformance
 class POPPLER_PRIVATE_EXPORT PDFDoc
 {
 public:
-    PDFDoc(const GooString *fileNameA, const GooString *ownerPassword = nullptr, const GooString *userPassword = nullptr, void *guiDataA = nullptr);
+    PDFDoc(const GooString *fileNameA, const GooString *ownerPassword = nullptr, const GooString *userPassword = nullptr, void *guiDataA = nullptr, const std::function<void()> &xrefReconstructedCallback = {});
 
 #ifdef _WIN32
-    PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword = nullptr, GooString *userPassword = nullptr, void *guiDataA = nullptr);
+    PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword = nullptr, GooString *userPassword = nullptr, void *guiDataA = nullptr, const std::function<void()> &xrefReconstructedCallback = {});
 #endif
 
-    PDFDoc(BaseStream *strA, const GooString *ownerPassword = nullptr, const GooString *userPassword = nullptr, void *guiDataA = nullptr);
+    PDFDoc(BaseStream *strA, const GooString *ownerPassword = nullptr, const GooString *userPassword = nullptr, void *guiDataA = nullptr, const std::function<void()> &xrefReconstructedCallback = {});
     ~PDFDoc();
 
     PDFDoc(const PDFDoc &) = delete;
@@ -344,7 +344,7 @@ private:
 
     PDFDoc();
     void init();
-    bool setup(const GooString *ownerPassword, const GooString *userPassword);
+    bool setup(const GooString *ownerPassword, const GooString *userPassword, const std::function<void()> &xrefReconstructedCallback);
     bool checkFooter();
     void checkHeader();
     bool checkEncryption(const GooString *ownerPassword, const GooString *userPassword);
diff --git a/poppler/XRef.cc b/poppler/XRef.cc
index 77a6752f..c7a509fb 100644
--- a/poppler/XRef.cc
+++ b/poppler/XRef.cc
@@ -258,12 +258,14 @@ XRef::XRef(const Object *trailerDictA) : XRef {}
         trailerDict = trailerDictA->copy();
 }
 
-XRef::XRef(BaseStream *strA, Goffset pos, Goffset mainXRefEntriesOffsetA, bool *wasReconstructed, bool reconstruct) : XRef {}
+XRef::XRef(BaseStream *strA, Goffset pos, Goffset mainXRefEntriesOffsetA, bool *wasReconstructed, bool reconstruct, const std::function<void()> &xrefReconstructedCallback) : XRef {}
 {
     Object obj;
 
     mainXRefEntriesOffset = mainXRefEntriesOffsetA;
 
+    xrefReconstructedCb = xrefReconstructedCallback;
+
     // read the trailer
     str = strA;
     start = str->getStart();
@@ -864,6 +866,10 @@ bool XRef::constructXRef(bool *wasReconstructed, bool needCatalogDict)
         *wasReconstructed = true;
     }
 
+    if (xrefReconstructedCb) {
+        xrefReconstructedCb();
+    }
+
     str->reset();
     while (true) {
         pos = str->getPos();
diff --git a/poppler/XRef.h b/poppler/XRef.h
index 1b050f8e..2b30b509 100644
--- a/poppler/XRef.h
+++ b/poppler/XRef.h
@@ -34,6 +34,8 @@
 #ifndef XREF_H
 #define XREF_H
 
+#include <functional>
+
 #include "poppler-config.h"
 #include "poppler_private_export.h"
 #include "Object.h"
@@ -101,7 +103,7 @@ public:
     // Constructor, create an empty XRef but with info dict, used for PDF writing
     XRef(const Object *trailerDictA);
     // Constructor.  Read xref table from stream.
-    XRef(BaseStream *strA, Goffset pos, Goffset mainXRefEntriesOffsetA = 0, bool *wasReconstructed = nullptr, bool reconstruct = false);
+    XRef(BaseStream *strA, Goffset pos, Goffset mainXRefEntriesOffsetA = 0, bool *wasReconstructed = nullptr, bool reconstruct = false, const std::function<void()> &xrefReconstructedCallback = {});
 
     // Destructor.
     ~XRef();
@@ -247,6 +249,7 @@ private:
     bool scannedSpecialFlags; // true if scanSpecialFlags has been called
     bool strOwner; // true if str is owned by the instance
     mutable std::recursive_mutex mutex;
+    std::function<void()> xrefReconstructedCb;
 
     int reserve(int newSize);
     int resize(int newSize);
diff --git a/qt5/demos/viewer.cpp b/qt5/demos/viewer.cpp
index 0b1a8f0e..72c83f64 100644
--- a/qt5/demos/viewer.cpp
+++ b/qt5/demos/viewer.cpp
@@ -44,6 +44,8 @@
 #include <QtWidgets/QMenuBar>
 #include <QtWidgets/QMessageBox>
 
+#include <functional>
+
 PdfViewer::PdfViewer(QWidget *parent) : QMainWindow(parent), m_currentPage(0), m_doc(nullptr)
 {
     setWindowTitle(tr("Poppler-Qt5 Demo"));
@@ -172,6 +174,8 @@ QSize PdfViewer::sizeHint() const
 
 void PdfViewer::loadDocument(const QString &file)
 {
+    // resetting xrefReconstructed each time we load new document
+    xrefReconstructed = false;
     Poppler::Document *newdoc = Poppler::Document::load(file);
     if (!newdoc) {
         QMessageBox msgbox(QMessageBox::Critical, tr("Open Error"), tr("Cannot open:\n") + file, QMessageBox::Ok, this);
@@ -196,6 +200,13 @@ void PdfViewer::loadDocument(const QString &file)
     m_doc->setRenderHint(Poppler::Document::TextAntialiasing, m_settingsTextAAAct->isChecked());
     m_doc->setRenderHint(Poppler::Document::Antialiasing, m_settingsGfxAAAct->isChecked());
     m_doc->setRenderBackend((Poppler::Document::RenderBackend)m_settingsRenderBackendGrp->checkedAction()->data().toInt());
+    if (m_doc->xrefWasReconstructed()) {
+        xrefReconstructedHandler(m_doc);
+    } else {
+        std::function<void()> cb = [this]() { xrefReconstructedHandler(m_doc); };
+
+        m_doc->setXRefReconstructedCallback(cb);
+    }
 
     Q_FOREACH (DocumentObserver *obs, m_observers) {
         obs->documentLoaded();
@@ -222,6 +233,16 @@ void PdfViewer::closeDocument()
     m_fileSaveCopyAct->setEnabled(false);
 }
 
+void PdfViewer::xrefReconstructedHandler(Poppler::Document *doc)
+{
+    if (!xrefReconstructed) {
+        QMessageBox msgbox(QMessageBox::Critical, tr("File may be corrupted"), tr("The PDF may be broken but we're still showing something, contents may not be correct"), QMessageBox::Ok, this);
+        msgbox.exec();
+
+        xrefReconstructed = true;
+    }
+}
+
 void PdfViewer::slotOpenFile()
 {
     QString fileName = QFileDialog::getOpenFileName(this, tr("Open PDF Document"), QDir::homePath(), tr("PDF Documents (*.pdf)"));
diff --git a/qt5/demos/viewer.h b/qt5/demos/viewer.h
index 105b1bbe..3e3d422d 100644
--- a/qt5/demos/viewer.h
+++ b/qt5/demos/viewer.h
@@ -56,8 +56,10 @@ private Q_SLOTS:
 private:
     void setPage(int page);
     int page() const;
+    void xrefReconstructedHandler(Poppler::Document *doc);
 
     int m_currentPage;
+    bool xrefReconstructed;
 
     QAction *m_fileOpenAct;
     QAction *m_fileSaveCopyAct;
diff --git a/qt5/src/poppler-document.cc b/qt5/src/poppler-document.cc
index 762eba9f..74dbd959 100644
--- a/qt5/src/poppler-document.cc
+++ b/qt5/src/poppler-document.cc
@@ -833,6 +833,16 @@ QVector<FormFieldSignature *> Document::signatures() const
     return result;
 }
 
+bool Document::xrefWasReconstructed() const
+{
+    return m_doc->xrefReconstructed;
+}
+
+void Document::setXRefReconstructedCallback(const std::function<void()> &callback)
+{
+    m_doc->xrefReconstructedCallback = callback;
+}
+
 QDateTime convertDate(const char *dateString)
 {
     int year, mon, day, hour, min, sec, tzHours, tzMins;
diff --git a/qt5/src/poppler-private.cc b/qt5/src/poppler-private.cc
index 695b9b8c..4896c29d 100644
--- a/qt5/src/poppler-private.cc
+++ b/qt5/src/poppler-private.cc
@@ -250,6 +250,8 @@ void DocumentData::init()
     paperColor = Qt::white;
     m_hints = 0;
     m_optContentModel = nullptr;
+    xrefReconstructed = false;
+    xrefReconstructedCallback = {};
 }
 
 void DocumentData::addTocChildren(QDomDocument *docSyn, QDomNode *parent, const std::vector<::OutlineItem *> *items)
@@ -282,6 +284,17 @@ void DocumentData::addTocChildren(QDomDocument *docSyn, QDomNode *parent, const
     }
 }
 
+void DocumentData::noitfyXRefReconstructed()
+{
+    if (!xrefReconstructed) {
+        xrefReconstructed = true;
+    }
+
+    if (xrefReconstructedCallback) {
+        xrefReconstructedCallback();
+    }
+}
+
 FormWidget *FormFieldData::getFormWidget(const FormField *f)
 {
     return f->m_formData->fm;
diff --git a/qt5/src/poppler-private.h b/qt5/src/poppler-private.h
index 3d503321..11302dd0 100644
--- a/qt5/src/poppler-private.h
+++ b/qt5/src/poppler-private.h
@@ -45,6 +45,7 @@
 #include <QtCore/QPointer>
 #include <QtCore/QVector>
 
+#include <functional>
 #include <config.h>
 #include <poppler-config.h>
 #include <GfxState.h>
@@ -106,10 +107,10 @@ public:
         m_filePath = filePath;
 
 #ifdef _WIN32
-        doc = new PDFDoc((wchar_t *)filePath.utf16(), filePath.length(), ownerPassword, userPassword);
+        doc = new PDFDoc((wchar_t *)filePath.utf16(), filePath.length(), ownerPassword, userPassword, nullptr, std::bind(&DocumentData::noitfyXRefReconstructed, this));
 #else
         GooString *fileName = new GooString(QFile::encodeName(filePath).constData());
-        doc = new PDFDoc(fileName, ownerPassword, userPassword);
+        doc = new PDFDoc(fileName, ownerPassword, userPassword, nullptr, std::bind(&DocumentData::noitfyXRefReconstructed, this));
 #endif
 
         delete ownerPassword;
@@ -121,7 +122,7 @@ public:
         m_device = device;
         QIODeviceInStream *str = new QIODeviceInStream(device, 0, false, device->size(), Object(objNull));
         init();
-        doc = new PDFDoc(str, ownerPassword, userPassword);
+        doc = new PDFDoc(str, ownerPassword, userPassword, nullptr, std::bind(&DocumentData::noitfyXRefReconstructed, this));
         delete ownerPassword;
         delete userPassword;
     }
@@ -132,7 +133,7 @@ public:
         fileContents = data;
         MemStream *str = new MemStream((char *)fileContents.data(), 0, fileContents.length(), Object(objNull));
         init();
-        doc = new PDFDoc(str, ownerPassword, userPassword);
+        doc = new PDFDoc(str, ownerPassword, userPassword, nullptr, std::bind(&DocumentData::noitfyXRefReconstructed, this));
         delete ownerPassword;
         delete userPassword;
     }
@@ -160,6 +161,13 @@ public:
         }
     }
 
+    /**
+     * a method that is being called whenever PDFDoc's XRef is reconstructed
+     * where we'll set xrefReconstructed flag and notify users of the
+     * reconstruction event
+     */
+    void noitfyXRefReconstructed();
+
     static Document *checkDocument(DocumentData *doc);
 
     PDFDoc *doc;
@@ -176,6 +184,9 @@ public:
     GfxLCMSProfilePtr m_sRGBProfile;
     GfxLCMSProfilePtr m_displayProfile;
 #endif
+    bool xrefReconstructed;
+    // notifies the user whenever the backend's PDFDoc XRef is reconstructed
+    std::function<void()> xrefReconstructedCallback;
 };
 
 class FontInfoData
diff --git a/qt5/src/poppler-qt5.h b/qt5/src/poppler-qt5.h
index 56bab8a2..5a375d6b 100644
--- a/qt5/src/poppler-qt5.h
+++ b/qt5/src/poppler-qt5.h
@@ -45,6 +45,8 @@
 #ifndef __POPPLER_QT_H__
 #define __POPPLER_QT_H__
 
+#include <functional>
+
 #include "poppler-annotation.h"
 #include "poppler-link.h"
 #include "poppler-optcontent.h"
@@ -1888,6 +1890,21 @@ QString subject = m_doc->info("Subject");
     */
     QVector<FormFieldSignature *> signatures() const;
 
+    /**
+     Returns whether the document's XRef table has been reconstructed or not
+
+     \since 21.06
+    */
+    bool xrefWasReconstructed() const;
+
+    /**
+     Sets the document's XRef reconstruction callback, so whenever a XRef table
+     reconstruction happens the callback will get triggered.
+
+     \since 21.06
+    */
+    void setXRefReconstructedCallback(const std::function<void()> &callback);
+
     /**
        Destructor.
     */
diff --git a/qt6/demos/viewer.cpp b/qt6/demos/viewer.cpp
index f1cfc852..7e5dedef 100644
--- a/qt6/demos/viewer.cpp
+++ b/qt6/demos/viewer.cpp
@@ -45,6 +45,8 @@
 #include <QMenuBar>
 #include <QMessageBox>
 
+#include <functional>
+
 PdfViewer::PdfViewer(QWidget *parent) : QMainWindow(parent), m_currentPage(0), m_doc(nullptr)
 {
     setWindowTitle(tr("Poppler-Qt6 Demo"));
@@ -168,6 +170,8 @@ QSize PdfViewer::sizeHint() const
 
 void PdfViewer::loadDocument(const QString &file)
 {
+    // resetting xrefReconstructed each time we load new document
+    xrefReconstructed = false;
     Poppler::Document *newdoc = Poppler::Document::load(file);
     if (!newdoc) {
         QMessageBox msgbox(QMessageBox::Critical, tr("Open Error"), tr("Cannot open:\n") + file, QMessageBox::Ok, this);
@@ -192,6 +196,13 @@ void PdfViewer::loadDocument(const QString &file)
     m_doc->setRenderHint(Poppler::Document::TextAntialiasing, m_settingsTextAAAct->isChecked());
     m_doc->setRenderHint(Poppler::Document::Antialiasing, m_settingsGfxAAAct->isChecked());
     m_doc->setRenderBackend((Poppler::Document::RenderBackend)m_settingsRenderBackendGrp->checkedAction()->data().toInt());
+    if (m_doc->xrefWasReconstructed()) {
+        xrefReconstructedHandler(m_doc);
+    } else {
+        std::function<void()> cb = [this]() { xrefReconstructedHandler(m_doc); };
+
+        m_doc->setXRefReconstructedCallback(cb);
+    }
 
     Q_FOREACH (DocumentObserver *obs, m_observers) {
         obs->documentLoaded();
@@ -218,6 +229,16 @@ void PdfViewer::closeDocument()
     m_fileSaveCopyAct->setEnabled(false);
 }
 
+void PdfViewer::xrefReconstructedHandler(Poppler::Document *doc)
+{
+    if (!xrefReconstructed) {
+        QMessageBox msgbox(QMessageBox::Critical, tr("File may be corrupted"), tr("The PDF may be broken but we're still showing something, contents may not be correct"), QMessageBox::Ok, this);
+        msgbox.exec();
+
+        xrefReconstructed = true;
+    }
+}
+
 void PdfViewer::slotOpenFile()
 {
     QString fileName = QFileDialog::getOpenFileName(this, tr("Open PDF Document"), QDir::homePath(), tr("PDF Documents (*.pdf)"));
diff --git a/qt6/demos/viewer.h b/qt6/demos/viewer.h
index 105b1bbe..3e3d422d 100644
--- a/qt6/demos/viewer.h
+++ b/qt6/demos/viewer.h
@@ -56,8 +56,10 @@ private Q_SLOTS:
 private:
     void setPage(int page);
     int page() const;
+    void xrefReconstructedHandler(Poppler::Document *doc);
 
     int m_currentPage;
+    bool xrefReconstructed;
 
     QAction *m_fileOpenAct;
     QAction *m_fileSaveCopyAct;
diff --git a/qt6/src/poppler-document.cc b/qt6/src/poppler-document.cc
index 8aaa0e79..d53269dd 100644
--- a/qt6/src/poppler-document.cc
+++ b/qt6/src/poppler-document.cc
@@ -815,6 +815,16 @@ QVector<FormFieldSignature *> Document::signatures() const
     return result;
 }
 
+bool Document::xrefWasReconstructed() const
+{
+    return m_doc->xrefReconstructed;
+}
+
+void Document::setXRefReconstructedCallback(const std::function<void()> &callback)
+{
+    m_doc->xrefReconstructedCallback = callback;
+}
+
 QDateTime convertDate(const char *dateString)
 {
     int year, mon, day, hour, min, sec, tzHours, tzMins;
diff --git a/qt6/src/poppler-private.cc b/qt6/src/poppler-private.cc
index a2971adc..01ae79e5 100644
--- a/qt6/src/poppler-private.cc
+++ b/qt6/src/poppler-private.cc
@@ -193,6 +193,19 @@ void DocumentData::init()
     paperColor = Qt::white;
     m_hints = 0;
     m_optContentModel = nullptr;
+    xrefReconstructed = false;
+    xrefReconstructedCallback = {};
+}
+
+void DocumentData::noitfyXRefReconstructed()
+{
+    if (!xrefReconstructed) {
+        xrefReconstructed = true;
+    }
+
+    if (xrefReconstructedCallback) {
+        xrefReconstructedCallback();
+    }
 }
 
 FormWidget *FormFieldData::getFormWidget(const FormField *f)
diff --git a/qt6/src/poppler-private.h b/qt6/src/poppler-private.h
index e1cff9c6..5ee724aa 100644
--- a/qt6/src/poppler-private.h
+++ b/qt6/src/poppler-private.h
@@ -45,6 +45,7 @@
 #include <QtCore/QPointer>
 #include <QtCore/QVector>
 
+#include <functional>
 #include <config.h>
 #include <poppler-config.h>
 #include <GfxState.h>
@@ -106,10 +107,10 @@ public:
         m_filePath = filePath;
 
 #ifdef _WIN32
-        doc = new PDFDoc((wchar_t *)filePath.utf16(), filePath.length(), ownerPassword, userPassword);
+        doc = new PDFDoc((wchar_t *)filePath.utf16(), filePath.length(), ownerPassword, userPassword, nullptr, std::bind(&DocumentData::noitfyXRefReconstructed, this));
 #else
         GooString *fileName = new GooString(QFile::encodeName(filePath).constData());
-        doc = new PDFDoc(fileName, ownerPassword, userPassword);
+        doc = new PDFDoc(fileName, ownerPassword, userPassword, nullptr, std::bind(&DocumentData::noitfyXRefReconstructed, this));
 #endif
 
         delete ownerPassword;
@@ -121,7 +122,7 @@ public:
         m_device = device;
         QIODeviceInStream *str = new QIODeviceInStream(device, 0, false, device->size(), Object(objNull));
         init();
-        doc = new PDFDoc(str, ownerPassword, userPassword);
+        doc = new PDFDoc(str, ownerPassword, userPassword, nullptr, std::bind(&DocumentData::noitfyXRefReconstructed, this));
         delete ownerPassword;
         delete userPassword;
     }
@@ -132,7 +133,7 @@ public:
         fileContents = data;
         MemStream *str = new MemStream((char *)fileContents.data(), 0, fileContents.length(), Object(objNull));
         init();
-        doc = new PDFDoc(str, ownerPassword, userPassword);
+        doc = new PDFDoc(str, ownerPassword, userPassword, nullptr, std::bind(&DocumentData::noitfyXRefReconstructed, this));
         delete ownerPassword;
         delete userPassword;
     }
@@ -158,6 +159,13 @@ public:
         }
     }
 
+    /**
+     * a method that is being called whenever PDFDoc's XRef is reconstructed
+     * where we'll set xrefReconstructed flag and notify users of the
+     * reconstruction event
+     */
+    void noitfyXRefReconstructed();
+
     static Document *checkDocument(DocumentData *doc);
 
     PDFDoc *doc;
@@ -174,6 +182,9 @@ public:
     GfxLCMSProfilePtr m_sRGBProfile;
     GfxLCMSProfilePtr m_displayProfile;
 #endif
+    bool xrefReconstructed;
+    // notifies the user whenever the backend's PDFDoc XRef is reconstructed
+    std::function<void()> xrefReconstructedCallback;
 };
 
 class FontInfoData
diff --git a/qt6/src/poppler-qt6.h b/qt6/src/poppler-qt6.h
index dbef56ae..565c2c19 100644
--- a/qt6/src/poppler-qt6.h
+++ b/qt6/src/poppler-qt6.h
@@ -45,6 +45,8 @@
 #ifndef __POPPLER_QT_H__
 #define __POPPLER_QT_H__
 
+#include <functional>
+
 #include "poppler-annotation.h"
 #include "poppler-link.h"
 #include "poppler-optcontent.h"
@@ -1723,6 +1725,21 @@ QString subject = m_doc->info("Subject");
     */
     QVector<FormFieldSignature *> signatures() const;
 
+    /**
+     Returns whether the document's XRef table has been reconstructed or not
+
+     \since 21.06
+    */
+    bool xrefWasReconstructed() const;
+
+    /**
+     Sets the document's XRef reconstruction callback, so whenever a XRef table
+     reconstruction happens the callback will get triggered.
+
+     \since 21.06
+    */
+    void setXRefReconstructedCallback(const std::function<void()> &callback);
+
     /**
        Destructor.
     */


More information about the poppler mailing list