[poppler] 9 commits - CMakeLists.txt glib/poppler-attachment.cc glib/poppler-attachment.h glib/poppler-document.cc glib/poppler-document.h glib/poppler-media.cc glib/poppler-media.h glib/poppler-page.cc glib/poppler-private.h glib/reference goo/gfile.cc goo/gfile.h poppler/FDPDFDocBuilder.cc poppler/FDPDFDocBuilder.h poppler/FILECacheLoader.cc poppler/FILECacheLoader.h poppler/PDFDocFactory.cc poppler/PSOutputDev.cc poppler/PSOutputDev.h poppler/StdinCachedFile.cc poppler/StdinCachedFile.h poppler/StdinPDFDocBuilder.cc poppler/StdinPDFDocBuilder.h poppler/Stream.h test/gtk-test.cc

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Nov 18 23:15:35 UTC 2021


 CMakeLists.txt                      |    8 -
 glib/poppler-attachment.cc          |   46 +++++++++
 glib/poppler-attachment.h           |    2 
 glib/poppler-document.cc            |  177 +++++++++++++++++++++++++++++++++++-
 glib/poppler-document.h             |    7 +
 glib/poppler-media.cc               |   47 +++++++++
 glib/poppler-media.h                |    2 
 glib/poppler-page.cc                |    9 +
 glib/poppler-private.h              |    1 
 glib/reference/poppler-docs.sgml    |   17 +++
 glib/reference/poppler-sections.txt |    5 +
 goo/gfile.cc                        |    7 +
 goo/gfile.h                         |    3 
 poppler/FDPDFDocBuilder.cc          |   56 +++++++++++
 poppler/FDPDFDocBuilder.h           |   17 ++-
 poppler/FILECacheLoader.cc          |   19 ++-
 poppler/FILECacheLoader.h           |   16 ++-
 poppler/PDFDocFactory.cc            |    4 
 poppler/PSOutputDev.cc              |   43 ++++++++
 poppler/PSOutputDev.h               |    4 
 poppler/StdinPDFDocBuilder.cc       |   36 -------
 poppler/Stream.h                    |    2 
 test/gtk-test.cc                    |   57 +++++++----
 23 files changed, 499 insertions(+), 86 deletions(-)

New commits:
commit 5914c1d6e8a8dddbb176f37552a4efb27445b909
Author: Christian Persch <chpe at src.gnome.org>
Date:   Sat Nov 13 11:03:48 2021 +0100

    glib: Add APIs to save to file descriptor

diff --git a/glib/poppler-attachment.cc b/glib/poppler-attachment.cc
index 3195483b..b44edded 100644
--- a/glib/poppler-attachment.cc
+++ b/glib/poppler-attachment.cc
@@ -227,7 +227,8 @@ static gboolean save_helper(const gchar *buf, gsize count, gpointer data, GError
 
     n = fwrite(buf, 1, count, f);
     if (n != count) {
-        g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno), _("Error writing to image file: %s"), g_strerror(errno));
+        int errsv = errno;
+        g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errsv), _("Error writing to image file: %s"), g_strerror(errsv));
         return FALSE;
     }
 
@@ -274,6 +275,49 @@ gboolean poppler_attachment_save(PopplerAttachment *attachment, const char *file
     return result;
 }
 
+/**
+ * poppler_attachment_save_to_fd:
+ * @attachment: A #PopplerAttachment.
+ * @fd: a valid file descriptor open for writing
+ * @error: (allow-none): return location for error, or %NULL.
+ *
+ * Saves @attachment to a file referred to by @fd.  If @error is set, %FALSE
+ * will be returned. Possible errors include those in the #G_FILE_ERROR domain
+ * and whatever the save function generates.
+ * Note that this function takes ownership of @fd; you must not operate on it
+ * again, nor close it.
+ *
+ * Return value: %TRUE, if the file successfully saved
+ *
+ * Since: 21.12.0
+ **/
+gboolean poppler_attachment_save_to_fd(PopplerAttachment *attachment, int fd, GError **error)
+{
+    gboolean result;
+    FILE *f;
+
+    g_return_val_if_fail(POPPLER_IS_ATTACHMENT(attachment), FALSE);
+    g_return_val_if_fail(fd != -1, FALSE);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+    f = fdopen(fd, "wb");
+    if (f == nullptr) {
+        int errsv = errno;
+        g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errsv), _("Failed to open FD %d for writing: %s"), fd, g_strerror(errsv));
+        return FALSE;
+    }
+
+    result = poppler_attachment_save_to_callback(attachment, save_helper, f, error);
+
+    if (fclose(f) < 0) {
+        int errsv = errno;
+        g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errsv), _("Failed to close FD %d, all data may not have been saved: %s"), fd, g_strerror(errsv));
+        return FALSE;
+    }
+
+    return result;
+}
+
 #define BUF_SIZE 1024
 
 /**
diff --git a/glib/poppler-attachment.h b/glib/poppler-attachment.h
index 5505a959..b04b3f7b 100644
--- a/glib/poppler-attachment.h
+++ b/glib/poppler-attachment.h
@@ -112,6 +112,8 @@ gsize poppler_attachment_get_size(PopplerAttachment *attachment);
 POPPLER_PUBLIC
 gboolean poppler_attachment_save(PopplerAttachment *attachment, const char *filename, GError **error);
 POPPLER_PUBLIC
+gboolean poppler_attachment_save_to_fd(PopplerAttachment *attachment, int fd, GError **error);
+POPPLER_PUBLIC
 gboolean poppler_attachment_save_to_callback(PopplerAttachment *attachment, PopplerAttachmentSaveFunc save_func, gpointer user_data, GError **error);
 
 G_END_DECLS
diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc
index f37ef79f..fd95a468 100644
--- a/glib/poppler-document.cc
+++ b/glib/poppler-document.cc
@@ -579,6 +579,54 @@ gboolean poppler_document_save_a_copy(PopplerDocument *document, const char *uri
     return retval;
 }
 
+/**
+ * poppler_document_save_to_fd:
+ * @document: a #PopplerDocument
+ * @fd: a valid file descriptor open for writing
+ * @include_changes: whether to include user changes (e.g. form fills)
+ * @error: (allow-none): return location for an error, or %NULL
+ *
+ * Saves @document. Any change made in the document such as
+ * form fields filled, annotations added or modified
+ * will be saved if @include_changes is %TRUE, or discarded i
+ * @include_changes is %FALSE.
+ *
+ * Note that this function takes ownership of @fd; you must not operate on it
+ * again, nor close it.
+ *
+ * If @error is set, %FALSE will be returned. Possible errors
+ * include those in the #G_FILE_ERROR domain.
+ *
+ * Return value: %TRUE, if the document was successfully saved
+ *
+ * Since: 21.12.0
+ **/
+gboolean poppler_document_save_to_fd(PopplerDocument *document, int fd, gboolean include_changes, GError **error)
+{
+    FILE *file;
+    OutStream *stream;
+    int rv;
+
+    g_return_val_if_fail(POPPLER_IS_DOCUMENT(document), FALSE);
+    g_return_val_if_fail(fd != -1, FALSE);
+
+    file = fdopen(fd, "wb");
+    if (file == nullptr) {
+        int errsv = errno;
+        g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errsv), "Failed to open FD %d for writing: %s", fd, g_strerror(errsv));
+        return FALSE;
+    }
+
+    stream = new FileOutStream(file, 0);
+    if (include_changes)
+        rv = document->doc->saveAs(stream);
+    else
+        rv = document->doc->saveWithoutChangesAs(stream);
+    delete stream;
+
+    return handle_save_error(rv, error);
+}
+
 static void poppler_document_finalize(GObject *object)
 {
     PopplerDocument *document = POPPLER_DOCUMENT(object);
@@ -3390,6 +3438,8 @@ static void poppler_ps_file_class_init(PopplerPSFileClass *klass)
 static void poppler_ps_file_init(PopplerPSFile *ps_file)
 {
     ps_file->out = nullptr;
+    ps_file->fd = -1;
+    ps_file->filename = nullptr;
     ps_file->paper_width = -1;
     ps_file->paper_height = -1;
     ps_file->duplex = FALSE;
@@ -3402,6 +3452,8 @@ static void poppler_ps_file_finalize(GObject *object)
     delete ps_file->out;
     g_object_unref(ps_file->document);
     g_free(ps_file->filename);
+    if (ps_file->fd != -1)
+        close(ps_file->fd);
 
     G_OBJECT_CLASS(poppler_ps_file_parent_class)->finalize(object);
 }
@@ -3415,7 +3467,7 @@ static void poppler_ps_file_finalize(GObject *object)
  *
  * Create a new postscript file to render to
  *
- * Return value: a PopplerPSFile
+ * Return value: (transfer full): a PopplerPSFile
  **/
 PopplerPSFile *poppler_ps_file_new(PopplerDocument *document, const char *filename, int first_page, int n_pages)
 {
@@ -3434,6 +3486,38 @@ PopplerPSFile *poppler_ps_file_new(PopplerDocument *document, const char *filena
     return ps_file;
 }
 
+/**
+ * poppler_ps_file_new_fd:
+ * @document: a #PopplerDocument
+ * @fd: a valid file descriptor open for writing
+ * @first_page: the first page to print
+ * @n_pages: the number of pages to print
+ *
+ * Create a new postscript file to render to.
+ * Note that this function takes ownership of @fd; you must not operate on it
+ * again, nor close it.
+ *
+ * Return value: (transfer full): a #PopplerPSFile
+ *
+ * Since: 21.12.0
+ **/
+PopplerPSFile *poppler_ps_file_new_fd(PopplerDocument *document, int fd, int first_page, int n_pages)
+{
+    PopplerPSFile *ps_file;
+
+    g_return_val_if_fail(POPPLER_IS_DOCUMENT(document), nullptr);
+    g_return_val_if_fail(fd != -1, nullptr);
+    g_return_val_if_fail(n_pages > 0, nullptr);
+
+    ps_file = (PopplerPSFile *)g_object_new(POPPLER_TYPE_PS_FILE, nullptr);
+    ps_file->document = (PopplerDocument *)g_object_ref(document);
+    ps_file->fd = fd;
+    ps_file->first_page = first_page + 1;
+    ps_file->last_page = first_page + 1 + n_pages - 1;
+
+    return ps_file;
+}
+
 /**
  * poppler_ps_file_set_paper_size:
  * @ps_file: a PopplerPSFile which was not yet printed to.
diff --git a/glib/poppler-document.h b/glib/poppler-document.h
index 177881df..5a0afd53 100644
--- a/glib/poppler-document.h
+++ b/glib/poppler-document.h
@@ -308,6 +308,8 @@ gboolean poppler_document_save(PopplerDocument *document, const char *uri, GErro
 POPPLER_PUBLIC
 gboolean poppler_document_save_a_copy(PopplerDocument *document, const char *uri, GError **error);
 POPPLER_PUBLIC
+gboolean poppler_document_save_to_fd(PopplerDocument *document, int fd, gboolean include_changes, GError **error);
+POPPLER_PUBLIC
 gboolean poppler_document_get_id(PopplerDocument *document, gchar **permanent_id, gchar **update_id);
 POPPLER_PUBLIC
 int poppler_document_get_n_pages(PopplerDocument *document);
@@ -498,6 +500,8 @@ GType poppler_ps_file_get_type(void) G_GNUC_CONST;
 POPPLER_PUBLIC
 PopplerPSFile *poppler_ps_file_new(PopplerDocument *document, const char *filename, int first_page, int n_pages);
 POPPLER_PUBLIC
+PopplerPSFile *poppler_ps_file_new_fd(PopplerDocument *document, int fd, int first_page, int n_pages);
+POPPLER_PUBLIC
 void poppler_ps_file_set_paper_size(PopplerPSFile *ps_file, double width, double height);
 POPPLER_PUBLIC
 void poppler_ps_file_set_duplex(PopplerPSFile *ps_file, gboolean duplex);
diff --git a/glib/poppler-media.cc b/glib/poppler-media.cc
index 6b827485..3966d6c0 100644
--- a/glib/poppler-media.cc
+++ b/glib/poppler-media.cc
@@ -225,7 +225,8 @@ static gboolean save_helper(const gchar *buf, gsize count, gpointer data, GError
 
     n = fwrite(buf, 1, count, f);
     if (n != count) {
-        g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno), "Error writing to media file: %s", g_strerror(errno));
+        int errsv = errno;
+        g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errsv), "Error writing to media file: %s", g_strerror(errsv));
         return FALSE;
     }
 
@@ -276,6 +277,50 @@ gboolean poppler_media_save(PopplerMedia *poppler_media, const char *filename, G
     return result;
 }
 
+/**
+ * poppler_media_save_to_fd:
+ * @poppler_media: a #PopplerMedia
+ * @fd: a valid file descriptor open for writing
+ * @error: (allow-none): return location for error, or %NULL.
+ *
+ * Saves embedded stream of @poppler_media to a file referred to by @fd.
+ * If @error is set, %FALSE will be returned.
+ * Possible errors include those in the #G_FILE_ERROR domain
+ * and whatever the save function generates.
+ * Note that this function takes ownership of @fd; you must not operate on it
+ * again, nor close it.
+ *
+ * Return value: %TRUE, if the file successfully saved
+ *
+ * Since: 21.12.0
+ */
+gboolean poppler_media_save_to_fd(PopplerMedia *poppler_media, int fd, GError **error)
+{
+    gboolean result;
+    FILE *f;
+
+    g_return_val_if_fail(POPPLER_IS_MEDIA(poppler_media), FALSE);
+    g_return_val_if_fail(poppler_media->stream.isStream(), FALSE);
+
+    f = fdopen(fd, "wb");
+
+    if (f == nullptr) {
+        int errsv = errno;
+        g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errsv), "Failed to open FD %d for writing: %s", fd, g_strerror(errsv));
+        return FALSE;
+    }
+
+    result = poppler_media_save_to_callback(poppler_media, save_helper, f, error);
+
+    if (fclose(f) < 0) {
+        int errsv = errno;
+        g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errsv), "Failed to close FD %d, all data may not have been saved: %s", fd, g_strerror(errsv));
+        return FALSE;
+    }
+
+    return result;
+}
+
 #define BUF_SIZE 1024
 
 /**
diff --git a/glib/poppler-media.h b/glib/poppler-media.h
index e4a278c6..3d54c785 100644
--- a/glib/poppler-media.h
+++ b/glib/poppler-media.h
@@ -69,6 +69,8 @@ gfloat poppler_media_get_repeat_count(PopplerMedia *poppler_media);
 POPPLER_PUBLIC
 gboolean poppler_media_save(PopplerMedia *poppler_media, const char *filename, GError **error);
 POPPLER_PUBLIC
+gboolean poppler_media_save_to_fd(PopplerMedia *poppler_media, int fd, GError **error);
+POPPLER_PUBLIC
 gboolean poppler_media_save_to_callback(PopplerMedia *poppler_media, PopplerMediaSaveFunc save_func, gpointer user_data, GError **error);
 
 G_END_DECLS
diff --git a/glib/poppler-page.cc b/glib/poppler-page.cc
index 684cc07f..a0efd6fa 100644
--- a/glib/poppler-page.cc
+++ b/glib/poppler-page.cc
@@ -1055,8 +1055,13 @@ void poppler_page_render_to_ps(PopplerPage *page, PopplerPSFile *ps_file)
         for (int i = ps_file->first_page; i <= ps_file->last_page; ++i) {
             pages.push_back(i);
         }
-        ps_file->out =
-                new PSOutputDev(ps_file->filename, ps_file->document->doc, nullptr, pages, psModePS, (int)ps_file->paper_width, (int)ps_file->paper_height, false, ps_file->duplex, 0, 0, 0, 0, psRasterizeWhenNeeded, false, nullptr, nullptr);
+        if (ps_file->fd != -1) {
+            ps_file->out =
+                    new PSOutputDev(ps_file->fd, ps_file->document->doc, nullptr, pages, psModePS, (int)ps_file->paper_width, (int)ps_file->paper_height, false, ps_file->duplex, 0, 0, 0, 0, psRasterizeWhenNeeded, false, nullptr, nullptr);
+        } else {
+            ps_file->out = new PSOutputDev(ps_file->filename, ps_file->document->doc, nullptr, pages, psModePS, (int)ps_file->paper_width, (int)ps_file->paper_height, false, ps_file->duplex, 0, 0, 0, 0, psRasterizeWhenNeeded, false,
+                                           nullptr, nullptr);
+        }
     }
 
     ps_file->document->doc->displayPage(ps_file->out, page->index + 1, 72.0, 72.0, 0, false, true, false);
diff --git a/glib/poppler-private.h b/glib/poppler-private.h
index 02967fbf..6c09d039 100644
--- a/glib/poppler-private.h
+++ b/glib/poppler-private.h
@@ -41,6 +41,7 @@ struct _PopplerPSFile
 
     PopplerDocument *document;
     PSOutputDev *out;
+    int fd;
     char *filename;
     int first_page;
     int last_page;
diff --git a/glib/reference/poppler-sections.txt b/glib/reference/poppler-sections.txt
index 9e6e17c3..f77aad35 100644
--- a/glib/reference/poppler-sections.txt
+++ b/glib/reference/poppler-sections.txt
@@ -202,6 +202,7 @@ poppler_document_new_from_stream
 poppler_document_reset_form
 poppler_document_save
 poppler_document_save_a_copy
+poppler_document_save_to_fd
 poppler_document_set_author
 poppler_document_set_creation_date
 poppler_document_set_creation_date_time
@@ -242,6 +243,7 @@ poppler_layers_iter_new
 poppler_layers_iter_next
 poppler_ps_file_free
 poppler_ps_file_new
+poppler_ps_file_new_fd
 poppler_ps_file_set_duplex
 poppler_ps_file_set_paper_size
 
@@ -344,6 +346,7 @@ poppler_attachment_get_mtime
 poppler_attachment_get_name
 poppler_attachment_get_size
 poppler_attachment_save
+poppler_attachment_save_to_fd
 poppler_attachment_save_to_callback
 
 <SUBSECTION Standard>
@@ -594,6 +597,7 @@ poppler_media_get_repeat_count
 poppler_media_get_show_controls
 poppler_media_is_embedded
 poppler_media_save
+poppler_media_save_to_fd
 poppler_media_save_to_callback
 
 <SUBSECTION Standard>
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index 1ae270ab..6c79513b 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -1143,6 +1143,49 @@ PSOutputDev::PSOutputDev(const char *fileName, PDFDoc *docA, char *psTitleA, con
     init(outputToFile, f, fileTypeA, psTitleA, docA, pagesA, modeA, imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA, paperWidthA, paperHeightA, noCropA, duplexA, levelA);
 }
 
+PSOutputDev::PSOutputDev(int fdA, PDFDoc *docA, char *psTitleA, const std::vector<int> &pagesA, PSOutMode modeA, int paperWidthA, int paperHeightA, bool noCropA, bool duplexA, int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+                         PSForceRasterize forceRasterizeA, bool manualCtrlA, PSOutCustomCodeCbk customCodeCbkA, void *customCodeCbkDataA, PSLevel levelA)
+{
+    FILE *f;
+    PSFileType fileTypeA;
+
+    underlayCbk = nullptr;
+    underlayCbkData = nullptr;
+    overlayCbk = nullptr;
+    overlayCbkData = nullptr;
+    customCodeCbk = customCodeCbkA;
+    customCodeCbkData = customCodeCbkDataA;
+
+    fontIDs = nullptr;
+    t1FontNames = nullptr;
+    font8Info = nullptr;
+    font16Enc = nullptr;
+    imgIDs = nullptr;
+    formIDs = nullptr;
+    paperSizes = nullptr;
+    embFontList = nullptr;
+    customColors = nullptr;
+    haveTextClip = false;
+    t3String = nullptr;
+    forceRasterize = forceRasterizeA;
+    psTitle = nullptr;
+
+    // open file or pipe
+    if (fdA == STDOUT_FILENO) {
+        fileTypeA = psStdout;
+        f = stdout;
+    } else {
+        fileTypeA = psFile;
+        if (!(f = fdopen(fdA, "w"))) {
+            error(errIO, -1, "Couldn't open PostScript file descriptor '{0:d}'", fdA);
+            ok = false;
+            return;
+        }
+    }
+
+    init(outputToFile, f, fileTypeA, psTitleA, docA, pagesA, modeA, imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA, paperWidthA, paperHeightA, noCropA, duplexA, levelA);
+}
+
 PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, char *psTitleA, PDFDoc *docA, const std::vector<int> &pagesA, PSOutMode modeA, int paperWidthA, int paperHeightA, bool noCropA, bool duplexA, int imgLLXA, int imgLLYA,
                          int imgURXA, int imgURYA, PSForceRasterize forceRasterizeA, bool manualCtrlA, PSOutCustomCodeCbk customCodeCbkA, void *customCodeCbkDataA, PSLevel levelA)
 {
diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h
index 6689a603..79769994 100644
--- a/poppler/PSOutputDev.h
+++ b/poppler/PSOutputDev.h
@@ -124,6 +124,10 @@ public:
                 int imgURXA = 0, int imgURYA = 0, PSForceRasterize forceRasterizeA = psRasterizeWhenNeeded, bool manualCtrlA = false, PSOutCustomCodeCbk customCodeCbkA = nullptr, void *customCodeCbkDataA = nullptr,
                 PSLevel levelA = psLevel2);
 
+    // Open a PSOutputDev that will write to a file descriptor
+    PSOutputDev(int fdA, PDFDoc *docA, char *psTitleA, const std::vector<int> &pages, PSOutMode modeA, int paperWidthA = -1, int paperHeightA = -1, bool noCrop = false, bool duplexA = true, int imgLLXA = 0, int imgLLYA = 0, int imgURXA = 0,
+                int imgURYA = 0, PSForceRasterize forceRasterizeA = psRasterizeWhenNeeded, bool manualCtrlA = false, PSOutCustomCodeCbk customCodeCbkA = nullptr, void *customCodeCbkDataA = nullptr, PSLevel levelA = psLevel2);
+
     // Open a PSOutputDev that will write to a generic stream.
     // pages has to be sorted in increasing order
     PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, char *psTitleA, PDFDoc *docA, const std::vector<int> &pages, PSOutMode modeA, int paperWidthA = -1, int paperHeightA = -1, bool noCrop = false, bool duplexA = true,
commit c3f1ece62ac52587308e44d3e170d864372875f2
Author: Christian Persch <chpe at src.gnome.org>
Date:   Sat Nov 13 11:03:48 2021 +0100

    glib: Add poppler_document_new_from_fd
    
    While it's already possible to create a PopplerDocument
    for STDIN by using fd://0 as the URI, it was not yet possible
    to create a PopplerDocument from a file descriptor.
    
    This adds poppler_document_new_from_fd(), which accepts
    a readable FD for a regular file, or for STDIN.
    
    Add a --fd option to test/gtk-test to test this. When used,
    gtk-test arguments are FD numbers instead of filenames or URIs.
    To test, use e.g.
    
    $ 3<test.pdf ./gtk-test --fd 3

diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc
index 38d89b71..f37ef79f 100644
--- a/glib/poppler-document.cc
+++ b/glib/poppler-document.cc
@@ -25,11 +25,21 @@
 #include "config.h"
 #include <cstring>
 
+#ifndef G_OS_WIN32
+#    include <fcntl.h>
+#    include <sys/stat.h>
+#    include <sys/types.h>
+#    include <unistd.h>
+#endif
+
 #ifndef __GI_SCANNER__
 #    include <memory>
 
+#    include <goo/gfile.h>
 #    include <splash/SplashBitmap.h>
+#    include <CachedFile.h>
 #    include <DateInfo.h>
+#    include <FILECacheLoader.h>
 #    include <GlobalParams.h>
 #    include <PDFDoc.h>
 #    include <Outline.h>
@@ -400,6 +410,87 @@ PopplerDocument *poppler_document_new_from_gfile(GFile *file, const char *passwo
     return document;
 }
 
+/**
+ * poppler_document_new_from_fd:
+ * @fd: a valid file descriptor
+ * @password: (allow-none): password to unlock the file with, or %NULL
+ * @error: (allow-none): Return location for an error, or %NULL
+ *
+ * Creates a new #PopplerDocument reading the PDF contents from the file
+ * descriptor @fd. @fd must refer to a regular file, or STDIN, and be open
+ * for reading.
+ * Possible errors include those in the #POPPLER_ERROR and #G_FILE_ERROR
+ * domains.
+ * Note that this function takes ownership of @fd; you must not operate on it
+ * again, nor close it.
+ *
+ * Returns: (transfer full): a new #PopplerDocument, or %NULL
+ *
+ * Since: 21.12.0
+ */
+PopplerDocument *poppler_document_new_from_fd(int fd, const char *password, GError **error)
+{
+#ifndef G_OS_WIN32
+    struct stat statbuf;
+    int flags;
+    BaseStream *stream;
+    PDFDoc *newDoc;
+    GooString *password_g;
+
+    g_return_val_if_fail(fd != -1, nullptr);
+
+    auto initer = std::make_unique<GlobalParamsIniter>(_poppler_error_cb);
+
+    if (fstat(fd, &statbuf) == -1 || (flags = fcntl(fd, F_GETFL, &flags)) == -1) {
+        int errsv = errno;
+        g_set_error_literal(error, G_FILE_ERROR, g_file_error_from_errno(errsv), g_strerror(errsv));
+        close(fd);
+        return nullptr;
+    }
+
+    switch (flags & O_ACCMODE) {
+    case O_RDONLY:
+    case O_RDWR:
+        break;
+    case O_WRONLY:
+    default:
+        g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_BADF, "File descriptor %d is not readable", fd);
+        close(fd);
+        return nullptr;
+    }
+
+    if (fd == STDIN_FILENO || !S_ISREG(statbuf.st_mode)) {
+        FILE *file;
+        if (fd == STDIN_FILENO) {
+            file = stdin;
+        } else {
+            file = fdopen(fd, "rb");
+            if (!file) {
+                int errsv = errno;
+                g_set_error_literal(error, G_FILE_ERROR, g_file_error_from_errno(errsv), g_strerror(errsv));
+                fclose(file);
+                return nullptr;
+            }
+        }
+
+        CachedFile *cachedFile = new CachedFile(new FILECacheLoader(file), nullptr);
+        stream = new CachedFileStream(cachedFile, 0, false, cachedFile->getLength(), Object(objNull));
+    } else {
+        GooFile *file = GooFile::open(fd);
+        stream = new FileStream(file, 0, false, file->size(), Object(objNull));
+    }
+
+    password_g = poppler_password_to_latin1(password);
+    newDoc = new PDFDoc(stream, password_g, password_g);
+    delete password_g;
+
+    return _poppler_document_new_from_pdfdoc(std::move(initer), newDoc, error);
+#else
+    g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Not supported on win32");
+    return nullptr;
+#endif /* G_OS_WIN32 */
+}
+
 static gboolean handle_save_error(int err_code, GError **error)
 {
     switch (err_code) {
diff --git a/glib/poppler-document.h b/glib/poppler-document.h
index 34d78d4c..177881df 100644
--- a/glib/poppler-document.h
+++ b/glib/poppler-document.h
@@ -290,6 +290,7 @@ typedef enum
 
 POPPLER_PUBLIC
 GType poppler_document_get_type(void) G_GNUC_CONST;
+
 POPPLER_PUBLIC
 PopplerDocument *poppler_document_new_from_file(const char *uri, const char *password, GError **error);
 POPPLER_PUBLIC
@@ -301,6 +302,8 @@ PopplerDocument *poppler_document_new_from_stream(GInputStream *stream, goffset
 POPPLER_PUBLIC
 PopplerDocument *poppler_document_new_from_gfile(GFile *file, const char *password, GCancellable *cancellable, GError **error);
 POPPLER_PUBLIC
+PopplerDocument *poppler_document_new_from_fd(int fd, const char *password, GError **error);
+POPPLER_PUBLIC
 gboolean poppler_document_save(PopplerDocument *document, const char *uri, GError **error);
 POPPLER_PUBLIC
 gboolean poppler_document_save_a_copy(PopplerDocument *document, const char *uri, GError **error);
diff --git a/glib/reference/poppler-sections.txt b/glib/reference/poppler-sections.txt
index 8ad07b09..9e6e17c3 100644
--- a/glib/reference/poppler-sections.txt
+++ b/glib/reference/poppler-sections.txt
@@ -195,6 +195,7 @@ poppler_document_has_javascript
 poppler_document_is_linearized
 poppler_document_new_from_bytes
 poppler_document_new_from_data
+poppler_document_new_from_fd
 poppler_document_new_from_file
 poppler_document_new_from_gfile
 poppler_document_new_from_stream
diff --git a/test/gtk-test.cc b/test/gtk-test.cc
index fcefd8b1..4c09a8d6 100644
--- a/test/gtk-test.cc
+++ b/test/gtk-test.cc
@@ -15,15 +15,18 @@
 #include <poppler.h>
 #include <poppler-private.h>
 #include <gtk/gtk.h>
+#include <cerrno>
 #include <cmath>
 
 static int requested_page = 0;
 static gboolean cairo_output = FALSE;
 static gboolean splash_output = FALSE;
+static gboolean args_are_fds = FALSE;
 static const char **file_arguments = nullptr;
 static const GOptionEntry options[] = { { "cairo", 'c', 0, G_OPTION_ARG_NONE, &cairo_output, "Cairo Output Device", nullptr },
                                         { "splash", 's', 0, G_OPTION_ARG_NONE, &splash_output, "Splash Output Device", nullptr },
                                         { "page", 'p', 0, G_OPTION_ARG_INT, &requested_page, "Page number", "PAGE" },
+                                        { "fd", 'f', 0, G_OPTION_ARG_NONE, &args_are_fds, "File descriptors", nullptr },
                                         { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &file_arguments, nullptr, "PDF-FILES…" },
                                         {} };
 
@@ -336,30 +339,48 @@ int main(int argc, char *argv[])
     for (int i = 0; file_arguments[i]; i++) {
         View *view;
         GFile *file;
-        PopplerDocument *doc;
+        PopplerDocument *doc = nullptr;
         GError *error = nullptr;
-
-        file = g_file_new_for_commandline_arg(file_arguments[i]);
-        doc = poppler_document_new_from_gfile(file, nullptr, nullptr, &error);
-        if (!doc) {
-            gchar *uri;
-
-            uri = g_file_get_uri(file);
-            g_printerr("Error opening document %s: %s\n", uri, error->message);
-            g_error_free(error);
-            g_free(uri);
+        const char *arg;
+
+        arg = file_arguments[i];
+        if (args_are_fds) {
+            char *end;
+            gint64 v;
+
+            errno = 0;
+            end = nullptr;
+            v = g_ascii_strtoll(arg, &end, 10);
+            if (errno || end == arg || v == -1 || v < G_MININT || v > G_MAXINT) {
+                g_set_error(&error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Failed to parse \"%s\" as file descriptor number", arg);
+            } else {
+                doc = poppler_document_new_from_fd(int(v), nullptr, &error);
+            }
+        } else {
+            file = g_file_new_for_commandline_arg(arg);
+            doc = poppler_document_new_from_gfile(file, nullptr, nullptr, &error);
+            if (!doc) {
+                gchar *uri;
+
+                uri = g_file_get_uri(file);
+                g_prefix_error(&error, "%s: ", uri);
+                g_free(uri);
+            }
             g_object_unref(file);
-
-            continue;
         }
-        g_object_unref(file);
 
-        view = view_new(doc);
-        view_list = g_list_prepend(view_list, view);
-        view_set_page(view, CLAMP(requested_page, 0, poppler_document_get_n_pages(doc) - 1));
+        if (doc) {
+            view = view_new(doc);
+            view_list = g_list_prepend(view_list, view);
+            view_set_page(view, CLAMP(requested_page, 0, poppler_document_get_n_pages(doc) - 1));
+        } else {
+            g_printerr("Error opening document: %s\n", error->message);
+            g_error_free(error);
+        }
     }
 
-    gtk_main();
+    if (view_list != nullptr)
+        gtk_main();
 
     return 0;
 }
commit 8d5d591d1910a60608bdbafd92179e8dec918bff
Author: Christian Persch <chpe at src.gnome.org>
Date:   Sat Nov 13 11:03:48 2021 +0100

    glib: docs: Add index for new API

diff --git a/glib/reference/poppler-docs.sgml b/glib/reference/poppler-docs.sgml
index 53be6d2d..c1b5e2b5 100644
--- a/glib/reference/poppler-docs.sgml
+++ b/glib/reference/poppler-docs.sgml
@@ -126,6 +126,10 @@
     <title>Index of new symbols in 21.05.0</title>
     <xi:include href="xml/api-index-21.05.0.xml"><xi:fallback /></xi:include>
   </index>
+  <index id="api-index-21-12-0">
+    <title>Index of new symbols in 21.12.0</title>
+    <xi:include href="xml/api-index-21.12.0.xml"><xi:fallback /></xi:include>
+  </index>
 
   <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
 </book>
commit 7db45fac4947e99c9f1985dfa3c82bd612d64cb0
Author: Christian Persch <chpe at src.gnome.org>
Date:   Sat Nov 13 11:03:48 2021 +0100

    glib: docs: Add missing API indices for new symbols

diff --git a/glib/reference/poppler-docs.sgml b/glib/reference/poppler-docs.sgml
index 102880ac..53be6d2d 100644
--- a/glib/reference/poppler-docs.sgml
+++ b/glib/reference/poppler-docs.sgml
@@ -114,7 +114,18 @@
     <title>Index of new symbols in 0.90</title>
     <xi:include href="xml/api-index-0.90.xml"><xi:fallback /></xi:include>
   </index>
-
+  <index id="api-index-20-04-0">
+    <title>Index of new symbols in 20.04.0</title>
+    <xi:include href="xml/api-index-20.04.0.xml"><xi:fallback /></xi:include>
+  </index>
+  <index id="api-index-20-09-0">
+    <title>Index of new symbols in 20.09.0</title>
+    <xi:include href="xml/api-index-20.09.0.xml"><xi:fallback /></xi:include>
+  </index>
+  <index id="api-index-21-05-0">
+    <title>Index of new symbols in 21.05.0</title>
+    <xi:include href="xml/api-index-21.05.0.xml"><xi:fallback /></xi:include>
+  </index>
 
   <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
 </book>
commit ff1b0aa530a1eb5b64119f3129434981bfc12e8e
Author: Christian Persch <chpe at src.gnome.org>
Date:   Sat Nov 13 11:03:48 2021 +0100

    build: Rename StdinPDFDocBuilder to FileDescriptorPDFDocBuilder
    
    ... since it's not for just stdin anymore.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0e0048cf..7e959305 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -407,6 +407,7 @@ set(poppler_SRCS
   poppler/Decrypt.cc
   poppler/Dict.cc
   poppler/Error.cc
+  poppler/FDPDFDocBuilder.cc
   poppler/FILECacheLoader.cc
   poppler/FileSpec.cc
   poppler/FontEncodingTables.cc
@@ -454,7 +455,6 @@ set(poppler_SRCS
   poppler/TextOutputDev.cc
   poppler/PageLabelInfo.cc
   poppler/SecurityHandler.cc
-  poppler/StdinPDFDocBuilder.cc
   poppler/Sound.cc
   poppler/ViewerPreferences.cc
   poppler/Movie.cc
@@ -614,6 +614,7 @@ if(ENABLE_UNSTABLE_API_ABI_HEADERS)
     poppler/Decrypt.h
     poppler/Dict.h
     poppler/Error.h
+    poppler/FDPDFDocBuilder.h
     poppler/FILECacheLoader.h
     poppler/FileSpec.h
     poppler/FontEncodingTables.h
@@ -672,7 +673,6 @@ if(ENABLE_UNSTABLE_API_ABI_HEADERS)
     poppler/PSOutputDev.h
     poppler/TextOutputDev.h
     poppler/SecurityHandler.h
-    poppler/StdinPDFDocBuilder.h
     poppler/BBoxOutputDev.h
     poppler/UTF.h
     poppler/Sound.h
diff --git a/poppler/StdinPDFDocBuilder.cc b/poppler/FDPDFDocBuilder.cc
similarity index 76%
rename from poppler/StdinPDFDocBuilder.cc
rename to poppler/FDPDFDocBuilder.cc
index ecf42b0f..4be7927b 100644
--- a/poppler/StdinPDFDocBuilder.cc
+++ b/poppler/FDPDFDocBuilder.cc
@@ -1,6 +1,6 @@
 //========================================================================
 //
-// StdinPDFDocBuilder.cc
+// FileDescriptorPDFDocBuilder.cc
 //
 // This file is licensed under the GPLv2 or later
 //
@@ -14,15 +14,15 @@
 
 #include <cstdio>
 
-#include "StdinPDFDocBuilder.h"
+#include "FDPDFDocBuilder.h"
 #include "FILECacheLoader.h"
 #include "CachedFile.h"
 
 //------------------------------------------------------------------------
-// StdinPDFDocBuilder
+// FileDescriptorPDFDocBuilder
 //------------------------------------------------------------------------
 
-int StdinPDFDocBuilder::parseFdFromUri(const GooString &uri)
+int FileDescriptorPDFDocBuilder::parseFdFromUri(const GooString &uri)
 {
     int fd = -1;
     char c;
@@ -32,7 +32,7 @@ int StdinPDFDocBuilder::parseFdFromUri(const GooString &uri)
     return fd;
 }
 
-std::unique_ptr<PDFDoc> StdinPDFDocBuilder::buildPDFDoc(const GooString &uri, GooString *ownerPassword, GooString *userPassword, void *guiDataA)
+std::unique_ptr<PDFDoc> FileDescriptorPDFDocBuilder::buildPDFDoc(const GooString &uri, GooString *ownerPassword, GooString *userPassword, void *guiDataA)
 {
     const auto fd = parseFdFromUri(uri);
     if (fd == -1)
@@ -50,7 +50,7 @@ std::unique_ptr<PDFDoc> StdinPDFDocBuilder::buildPDFDoc(const GooString &uri, Go
     return std::make_unique<PDFDoc>(new CachedFileStream(cachedFile, 0, false, cachedFile->getLength(), Object(objNull)), ownerPassword, userPassword);
 }
 
-bool StdinPDFDocBuilder::supports(const GooString &uri)
+bool FileDescriptorPDFDocBuilder::supports(const GooString &uri)
 {
     return parseFdFromUri(uri) != -1;
 }
diff --git a/poppler/StdinPDFDocBuilder.h b/poppler/FDPDFDocBuilder.h
similarity index 73%
rename from poppler/StdinPDFDocBuilder.h
rename to poppler/FDPDFDocBuilder.h
index 76c69ef1..f4a19bed 100644
--- a/poppler/StdinPDFDocBuilder.h
+++ b/poppler/FDPDFDocBuilder.h
@@ -1,6 +1,6 @@
 //========================================================================
 //
-// StdinPDFDocBuilder.h
+// FileDescriptorPDFDocBuilder.h
 //
 // This file is licensed under the GPLv2 or later
 //
@@ -10,18 +10,18 @@
 //
 //========================================================================
 
-#ifndef STDINPDFDOCBUILDER_H
-#define STDINPDFDOCBUILDER_H
+#ifndef FDPDFDOCBUILDER_H
+#define FDPDFDOCBUILDER_H
 
 #include "PDFDocBuilder.h"
 
 //------------------------------------------------------------------------
-// StdinPDFDocBuilder
+// FileDescriptorPDFDocBuilder
 //
-// The StdinPDFDocBuilder implements a PDFDocBuilder that read from a file descriptor.
+// The FileDescriptorPDFDocBuilder implements a PDFDocBuilder that read from a file descriptor.
 //------------------------------------------------------------------------
 
-class StdinPDFDocBuilder : public PDFDocBuilder
+class FileDescriptorPDFDocBuilder : public PDFDocBuilder
 {
 
 public:
@@ -32,4 +32,4 @@ private:
     int parseFdFromUri(const GooString &uri);
 };
 
-#endif /* STDINPDFDOCBUILDER_H */
+#endif /* FDPDFDOCBUILDER_H */
diff --git a/poppler/PDFDocFactory.cc b/poppler/PDFDocFactory.cc
index e4797074..a807ab3f 100644
--- a/poppler/PDFDocFactory.cc
+++ b/poppler/PDFDocFactory.cc
@@ -19,7 +19,7 @@
 #include "goo/GooString.h"
 #include "PDFDoc.h"
 #include "LocalPDFDocBuilder.h"
-#include "StdinPDFDocBuilder.h"
+#include "FDPDFDocBuilder.h"
 #ifdef ENABLE_LIBCURL
 #    include "CurlPDFDocBuilder.h"
 #endif
@@ -37,7 +37,7 @@ PDFDocFactory::PDFDocFactory(std::vector<PDFDocBuilder *> *pdfDocBuilders)
         builders = new std::vector<PDFDocBuilder *>();
     }
     builders->push_back(new LocalPDFDocBuilder());
-    builders->push_back(new StdinPDFDocBuilder());
+    builders->push_back(new FileDescriptorPDFDocBuilder());
 #ifdef ENABLE_LIBCURL
     builders->push_back(new CurlPDFDocBuilder());
 #endif
commit 661debdf700d7a13a8373f681e3729fcbb6aa573
Author: Christian Persch <chpe at src.gnome.org>
Date:   Sat Nov 13 11:03:48 2021 +0100

    build: Rename StdinCacheLoader to FILECacheLoader
    
    ... since it's not for just stdin anymore.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1f2e25ba..0e0048cf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -407,6 +407,7 @@ set(poppler_SRCS
   poppler/Decrypt.cc
   poppler/Dict.cc
   poppler/Error.cc
+  poppler/FILECacheLoader.cc
   poppler/FileSpec.cc
   poppler/FontEncodingTables.cc
   poppler/Form.cc
@@ -453,7 +454,6 @@ set(poppler_SRCS
   poppler/TextOutputDev.cc
   poppler/PageLabelInfo.cc
   poppler/SecurityHandler.cc
-  poppler/StdinCachedFile.cc
   poppler/StdinPDFDocBuilder.cc
   poppler/Sound.cc
   poppler/ViewerPreferences.cc
@@ -614,6 +614,7 @@ if(ENABLE_UNSTABLE_API_ABI_HEADERS)
     poppler/Decrypt.h
     poppler/Dict.h
     poppler/Error.h
+    poppler/FILECacheLoader.h
     poppler/FileSpec.h
     poppler/FontEncodingTables.h
     poppler/FontInfo.h
@@ -671,7 +672,6 @@ if(ENABLE_UNSTABLE_API_ABI_HEADERS)
     poppler/PSOutputDev.h
     poppler/TextOutputDev.h
     poppler/SecurityHandler.h
-    poppler/StdinCachedFile.h
     poppler/StdinPDFDocBuilder.h
     poppler/BBoxOutputDev.h
     poppler/UTF.h
diff --git a/poppler/StdinCachedFile.cc b/poppler/FILECacheLoader.cc
similarity index 79%
rename from poppler/StdinCachedFile.cc
rename to poppler/FILECacheLoader.cc
index 530bf931..fcacc2f4 100644
--- a/poppler/StdinCachedFile.cc
+++ b/poppler/FILECacheLoader.cc
@@ -1,6 +1,6 @@
 //========================================================================
 //
-// StdinCachedFile.cc
+// FILECacheLoader.cc
 //
 // This file is licensed under the GPLv2 or later
 //
@@ -13,22 +13,20 @@
 
 #include <config.h>
 
-#include "StdinCachedFile.h"
+#include "FILECacheLoader.h"
 
 #if defined(_WIN32) || defined(__CYGWIN__)
 #    include <fcntl.h> // for O_BINARY
 #    include <io.h> // for _setmode
 #endif
 
-StdinCacheLoader::~StdinCacheLoader()
+FILECacheLoader::~FILECacheLoader()
 {
-#ifndef _WIN32
     if (file != stdin)
         fclose(file);
-#endif
 }
 
-size_t StdinCacheLoader::init(GooString *dummy, CachedFile *cachedFile)
+size_t FILECacheLoader::init(GooString *dummy, CachedFile *cachedFile)
 {
     size_t read, size = 0;
     char buf[CachedFileChunkSize];
@@ -47,7 +45,7 @@ size_t StdinCacheLoader::init(GooString *dummy, CachedFile *cachedFile)
     return size;
 }
 
-int StdinCacheLoader::load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer)
+int FILECacheLoader::load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer)
 {
     return 0;
 }
diff --git a/poppler/StdinCachedFile.h b/poppler/FILECacheLoader.h
similarity index 66%
rename from poppler/StdinCachedFile.h
rename to poppler/FILECacheLoader.h
index f95c44fd..5ce0c150 100644
--- a/poppler/StdinCachedFile.h
+++ b/poppler/FILECacheLoader.h
@@ -1,6 +1,6 @@
 //========================================================================
 //
-// StdinCachedFile.h
+// FILECacheLoader.h
 //
 // This file is licensed under the GPLv2 or later
 //
@@ -9,22 +9,22 @@
 //
 //========================================================================
 
-#ifndef STDINCACHELOADER_H
-#define STDINCACHELOADER_H
+#ifndef FILECACHELOADER_H
+#define FILECACHELOADER_H
 
 #include "CachedFile.h"
 
 #include <cstdio>
 
-class POPPLER_PRIVATE_EXPORT StdinCacheLoader : public CachedFileLoader
+class POPPLER_PRIVATE_EXPORT FILECacheLoader : public CachedFileLoader
 {
     FILE *file = stdin;
 
 public:
-    StdinCacheLoader() = default;
-    ~StdinCacheLoader() override;
+    FILECacheLoader() = default;
+    ~FILECacheLoader() override;
 
-    explicit StdinCacheLoader(FILE *fileA) : file(fileA) { }
+    explicit FILECacheLoader(FILE *fileA) : file(fileA) { }
 
     size_t init(GooString *dummy, CachedFile *cachedFile) override;
     int load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer) override;
diff --git a/poppler/StdinPDFDocBuilder.cc b/poppler/StdinPDFDocBuilder.cc
index 02aefdbe..ecf42b0f 100644
--- a/poppler/StdinPDFDocBuilder.cc
+++ b/poppler/StdinPDFDocBuilder.cc
@@ -15,8 +15,8 @@
 #include <cstdio>
 
 #include "StdinPDFDocBuilder.h"
+#include "FILECacheLoader.h"
 #include "CachedFile.h"
-#include "StdinCachedFile.h"
 
 //------------------------------------------------------------------------
 // StdinPDFDocBuilder
@@ -46,7 +46,7 @@ std::unique_ptr<PDFDoc> StdinPDFDocBuilder::buildPDFDoc(const GooString &uri, Go
     if (!file)
         return {};
 
-    CachedFile *cachedFile = new CachedFile(new StdinCacheLoader(file), nullptr);
+    CachedFile *cachedFile = new CachedFile(new FILECacheLoader(file), nullptr);
     return std::make_unique<PDFDoc>(new CachedFileStream(cachedFile, 0, false, cachedFile->getLength(), Object(objNull)), ownerPassword, userPassword);
 }
 
commit 19a8e85d7d903fbc826416252b4fbce1644c65f8
Author: Christian Persch <chpe at src.gnome.org>
Date:   Sat Nov 13 11:03:48 2021 +0100

    poppler: Make StdinCacheLoader more generic
    
    Despite its name, StdinCacheLoader really works with any FILE*, not just
    stdin.  Add a constructor taking a FILE* to set the file it operates on.
    
    This will be used in glib/ in a subsequent commit.

diff --git a/poppler/StdinCachedFile.cc b/poppler/StdinCachedFile.cc
index a5110be0..530bf931 100644
--- a/poppler/StdinCachedFile.cc
+++ b/poppler/StdinCachedFile.cc
@@ -19,7 +19,14 @@
 #    include <fcntl.h> // for O_BINARY
 #    include <io.h> // for _setmode
 #endif
-#include <cstdio>
+
+StdinCacheLoader::~StdinCacheLoader()
+{
+#ifndef _WIN32
+    if (file != stdin)
+        fclose(file);
+#endif
+}
 
 size_t StdinCacheLoader::init(GooString *dummy, CachedFile *cachedFile)
 {
@@ -27,12 +34,12 @@ size_t StdinCacheLoader::init(GooString *dummy, CachedFile *cachedFile)
     char buf[CachedFileChunkSize];
 
 #if defined(_WIN32) || defined(__CYGWIN__)
-    _setmode(fileno(stdin), O_BINARY);
+    _setmode(fileno(file), O_BINARY);
 #endif
 
     CachedFileWriter writer = CachedFileWriter(cachedFile, nullptr);
     do {
-        read = fread(buf, 1, CachedFileChunkSize, stdin);
+        read = fread(buf, 1, CachedFileChunkSize, file);
         (writer.write)(buf, CachedFileChunkSize);
         size += read;
     } while (read == CachedFileChunkSize);
diff --git a/poppler/StdinCachedFile.h b/poppler/StdinCachedFile.h
index 7ce6dbc2..f95c44fd 100644
--- a/poppler/StdinCachedFile.h
+++ b/poppler/StdinCachedFile.h
@@ -14,10 +14,18 @@
 
 #include "CachedFile.h"
 
+#include <cstdio>
+
 class POPPLER_PRIVATE_EXPORT StdinCacheLoader : public CachedFileLoader
 {
+    FILE *file = stdin;
 
 public:
+    StdinCacheLoader() = default;
+    ~StdinCacheLoader() override;
+
+    explicit StdinCacheLoader(FILE *fileA) : file(fileA) { }
+
     size_t init(GooString *dummy, CachedFile *cachedFile) override;
     int load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer) override;
 };
diff --git a/poppler/StdinPDFDocBuilder.cc b/poppler/StdinPDFDocBuilder.cc
index b84420b2..02aefdbe 100644
--- a/poppler/StdinPDFDocBuilder.cc
+++ b/poppler/StdinPDFDocBuilder.cc
@@ -12,6 +12,8 @@
 
 #include <config.h>
 
+#include <cstdio>
+
 #include "StdinPDFDocBuilder.h"
 #include "CachedFile.h"
 #include "StdinCachedFile.h"
@@ -20,17 +22,35 @@
 // StdinPDFDocBuilder
 //------------------------------------------------------------------------
 
+int StdinPDFDocBuilder::parseFdFromUri(const GooString &uri)
+{
+    int fd = -1;
+    char c;
+    if (sscanf(uri.c_str(), "fd://%d%c", &fd, &c) != 1)
+        return -1;
+
+    return fd;
+}
+
 std::unique_ptr<PDFDoc> StdinPDFDocBuilder::buildPDFDoc(const GooString &uri, GooString *ownerPassword, GooString *userPassword, void *guiDataA)
 {
-    CachedFile *cachedFile = new CachedFile(new StdinCacheLoader(), nullptr);
+    const auto fd = parseFdFromUri(uri);
+    if (fd == -1)
+        return {};
+
+    FILE *file;
+    if (fd == STDIN_FILENO)
+        file = stdin;
+    else
+        file = fdopen(fd, "rb");
+    if (!file)
+        return {};
+
+    CachedFile *cachedFile = new CachedFile(new StdinCacheLoader(file), nullptr);
     return std::make_unique<PDFDoc>(new CachedFileStream(cachedFile, 0, false, cachedFile->getLength(), Object(objNull)), ownerPassword, userPassword);
 }
 
 bool StdinPDFDocBuilder::supports(const GooString &uri)
 {
-    if (uri.cmpN("fd://0", 6) == 0) {
-        return true;
-    } else {
-        return false;
-    }
+    return parseFdFromUri(uri) != -1;
 }
diff --git a/poppler/StdinPDFDocBuilder.h b/poppler/StdinPDFDocBuilder.h
index a4bbf8e4..76c69ef1 100644
--- a/poppler/StdinPDFDocBuilder.h
+++ b/poppler/StdinPDFDocBuilder.h
@@ -18,7 +18,7 @@
 //------------------------------------------------------------------------
 // StdinPDFDocBuilder
 //
-// The StdinPDFDocBuilder implements a PDFDocBuilder that read from stdin.
+// The StdinPDFDocBuilder implements a PDFDocBuilder that read from a file descriptor.
 //------------------------------------------------------------------------
 
 class StdinPDFDocBuilder : public PDFDocBuilder
@@ -27,6 +27,9 @@ class StdinPDFDocBuilder : public PDFDocBuilder
 public:
     std::unique_ptr<PDFDoc> buildPDFDoc(const GooString &uri, GooString *ownerPassword = nullptr, GooString *userPassword = nullptr, void *guiDataA = nullptr) override;
     bool supports(const GooString &uri) override;
+
+private:
+    int parseFdFromUri(const GooString &uri);
 };
 
 #endif /* STDINPDFDOCBUILDER_H */
commit dc50059c757ae5c58b45755dc4f035e620679252
Author: Christian Persch <chpe at src.gnome.org>
Date:   Sat Nov 13 11:03:48 2021 +0100

    poppler: Export StdinCacheLoader and FileStream
    
    They will be used in glib/ in a subsequent commit.

diff --git a/poppler/StdinCachedFile.h b/poppler/StdinCachedFile.h
index 7c12e1bf..7ce6dbc2 100644
--- a/poppler/StdinCachedFile.h
+++ b/poppler/StdinCachedFile.h
@@ -14,7 +14,7 @@
 
 #include "CachedFile.h"
 
-class StdinCacheLoader : public CachedFileLoader
+class POPPLER_PRIVATE_EXPORT StdinCacheLoader : public CachedFileLoader
 {
 
 public:
diff --git a/poppler/Stream.h b/poppler/Stream.h
index 97ce5ea0..0ab56b6e 100644
--- a/poppler/Stream.h
+++ b/poppler/Stream.h
@@ -516,7 +516,7 @@ private:
 
 #define fileStreamBufSize 256
 
-class FileStream : public BaseStream
+class POPPLER_PRIVATE_EXPORT FileStream : public BaseStream
 {
 public:
     FileStream(GooFile *fileA, Goffset startA, bool limitedA, Goffset lengthA, Object &&dictA);
commit b01d37e14138de096212ae283840b580718966e7
Author: Christian Persch <chpe at src.gnome.org>
Date:   Sat Nov 13 11:03:48 2021 +0100

    gfile: Add GooFile constructor taking a file descriptor

diff --git a/goo/gfile.cc b/goo/gfile.cc
index 98fe7b7f..98e1a2f9 100644
--- a/goo/gfile.cc
+++ b/goo/gfile.cc
@@ -404,7 +404,12 @@ GooFile *GooFile::open(const std::string &fileName)
 {
     int fd = openFileDescriptor(fileName.c_str(), O_RDONLY);
 
-    return fd < 0 ? nullptr : new GooFile(fd);
+    return GooFile::open(fd);
+}
+
+GooFile *GooFile::open(int fdA)
+{
+    return fdA < 0 ? nullptr : new GooFile(fdA);
 }
 
 GooFile::GooFile(int fdA) : fd(fdA)
diff --git a/goo/gfile.h b/goo/gfile.h
index d04b9ac6..a3650a4e 100644
--- a/goo/gfile.h
+++ b/goo/gfile.h
@@ -123,6 +123,9 @@ public:
     Goffset size() const;
 
     static GooFile *open(const std::string &fileName);
+#ifndef _WIN32
+    static GooFile *open(int fdA);
+#endif
 
 #ifdef _WIN32
     static GooFile *open(const wchar_t *fileName);


More information about the poppler mailing list