From 3bd1f8e319cc5fc96c141dff052bcb41f525caed Mon Sep 17 00:00:00 2001
From: Christian Persch <chpe@src.gnome.org>
Date: Thu, 16 Aug 2018 23:02:58 +0200
Subject: [PATCH 1/3] gfile: Enable inclusion together with glib.h

GDir class name conflicts with a glib type. Surround
its definition with GFILE_NO_GDIR, so that source code
in glib/ can define that before including gfile.h and
not get the conflict.
---
 goo/gfile.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/goo/gfile.h b/goo/gfile.h
index 4ce805e..0f02180 100644
--- a/goo/gfile.h
+++ b/goo/gfile.h
@@ -175,6 +175,8 @@ private:
 // GDir and GDirEntry
 //------------------------------------------------------------------------
 
+#ifndef GFILE_NO_GDIR
+
 class GDirEntry {
 public:
 
@@ -220,4 +222,6 @@ private:
 #endif
 };
 
+#endif /* !GFILE_NO_GDIR */
+
 #endif
-- 
2.9.4


From 76f531346c873d64b9f15485210c30fe39da9a92 Mon Sep 17 00:00:00 2001
From: Christian Persch <chpe@src.gnome.org>
Date: Thu, 16 Aug 2018 23:02:58 +0200
Subject: [PATCH 2/3] 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
---
 glib/poppler-document.cc            | 89 +++++++++++++++++++++++++++++++++++++
 glib/poppler-document.h             |  3 ++
 glib/reference/poppler-docs.sgml    |  4 ++
 glib/reference/poppler-sections.txt |  1 +
 goo/gfile.cc                        |  9 ++++
 goo/gfile.h                         |  5 ++-
 test/gtk-test.cc                    | 56 ++++++++++++++++-------
 7 files changed, 148 insertions(+), 19 deletions(-)

diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc
index b343eb9..d986452 100644
--- a/glib/poppler-document.cc
+++ b/glib/poppler-document.cc
@@ -20,8 +20,14 @@
 
 #include "config.h"
 #include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #ifndef __GI_SCANNER__
+#define GFILE_NO_GDIR
+#include <goo/gfile.h>
 #include <goo/GooList.h>
 #include <splash/SplashBitmap.h>
 #include <DateInfo.h>
@@ -36,6 +42,8 @@
 #include <FontInfo.h>
 #include <PDFDocEncoding.h>
 #include <OptionalContent.h>
+#include <CachedFile.h>
+#include <StdinCachedFile.h>
 #endif
 
 #include "poppler.h"
@@ -357,6 +365,87 @@ poppler_document_new_from_gfile (GFile        *file,
   return document;
 }
 
+/**
+ * poppler_document_new_from_fd:
+ * @file: 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 ownership of @fd; you must not operate on it
+ * again, or close it.
+ *
+ * Returns: (transfer full): a new #PopplerDocument, or %NULL
+ *
+ * Since: 0.68
+ */
+PopplerDocument *
+poppler_document_new_from_fd (int           fd,
+			      const char   *password,
+			      GError      **error)
+{
+  struct stat statbuf;
+  int flags;
+  BaseStream *stream;
+  PDFDoc *newDoc;
+  GooString *password_g;
+
+  g_return_val_if_fail(fd != -1, NULL);
+
+  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 FALSE;
+  }
+
+  if (fd != STDIN_FILENO && !S_ISREG(statbuf.st_mode)) {
+    g_set_error_literal(error, G_FILE_ERROR, G_FILE_ERROR_BADF,
+			"Not a regular file.");
+    close(fd);
+    return FALSE;
+  }
+
+  switch (flags & O_ACCMODE) {
+  case O_RDONLY:
+  case O_RDWR:
+    break;
+  case O_WRONLY:
+  default:
+    g_set_error_literal(error, G_FILE_ERROR, G_FILE_ERROR_BADF,
+			"Not a readable file descriptor.");
+    close(fd);
+    return FALSE;
+  }
+
+  if (!globalParams) {
+    globalParams = new GlobalParams();
+  }
+
+  if (fd == STDIN_FILENO) {
+    CachedFile *cachedFile = new CachedFile(new StdinCacheLoader(), nullptr);
+    stream = new CachedFileStream(cachedFile, 0, gFalse, cachedFile->getLength(),
+				  Object(objNull));
+  } else {
+    GooFile *file = GooFile::open(fd);
+    stream = new FileStream(file, 0, gFalse, 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 (newDoc, error);
+}
+
 static gboolean
 handle_save_error (int      err_code,
 		   GError **error)
diff --git a/glib/poppler-document.h b/glib/poppler-document.h
index a7fcea1..aaa13d9 100644
--- a/glib/poppler-document.h
+++ b/glib/poppler-document.h
@@ -184,6 +184,9 @@ PopplerDocument   *poppler_document_new_from_gfile         (GFile           *fil
                                                             const char      *password,
                                                             GCancellable    *cancellable,
                                                             GError         **error);
+PopplerDocument   *poppler_document_new_from_fd            (int              fd,
+							    const char      *password,
+							    GError         **error);
 gboolean           poppler_document_save                   (PopplerDocument *document,
 							    const char      *uri,
 							    GError         **error);
diff --git a/glib/reference/poppler-docs.sgml b/glib/reference/poppler-docs.sgml
index 5db818f..0b031dc 100644
--- a/glib/reference/poppler-docs.sgml
+++ b/glib/reference/poppler-docs.sgml
@@ -73,6 +73,10 @@
     <title>Index of new symbols in 0.46</title>
     <xi:include href="xml/api-index-0.46.xml"><xi:fallback /></xi:include>
   </index>
+  <index id="api-index-0-68">
+    <title>Index of new symbols in 0.68</title>
+    <xi:include href="xml/api-index-0.68.xml"><xi:fallback /></xi:include>
+  </index>
 
   <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
 </book>
diff --git a/glib/reference/poppler-sections.txt b/glib/reference/poppler-sections.txt
index af1bbba..8fe501c 100644
--- a/glib/reference/poppler-sections.txt
+++ b/glib/reference/poppler-sections.txt
@@ -128,6 +128,7 @@ poppler_document_new_from_file
 poppler_document_new_from_data
 poppler_document_new_from_stream
 poppler_document_new_from_gfile
+poppler_document_new_from_fd
 poppler_document_save
 poppler_document_save_a_copy
 poppler_document_get_id
diff --git a/goo/gfile.cc b/goo/gfile.cc
index 381a0ce..4a7bcea 100644
--- a/goo/gfile.cc
+++ b/goo/gfile.cc
@@ -682,6 +682,10 @@ GooFile* GooFile::open(const wchar_t *fileName) {
   return handle == INVALID_HANDLE_VALUE ? nullptr : new GooFile(handle);
 }
 
+GooFile* GooFile::open(int fd) {
+  return nullptr;
+}
+
 bool GooFile::modificationTimeChangedSinceOpen() const
 {
   struct _FILETIME lastModified;
@@ -718,10 +722,15 @@ GooFile* GooFile::open(const GooString *fileName) {
   return fd < 0 ? nullptr : new GooFile(fd);
 }
 
+GooFile* GooFile::open(int fd) {
+  return fd == -1 ? nullptr : new GooFile(fd);
+}
+
 GooFile::GooFile(int fdA)
  : fd(fdA)
 {
     struct stat statbuf;
+
     fstat(fd, &statbuf);
     modifiedTimeOnOpen = mtim(statbuf);
 }
diff --git a/goo/gfile.h b/goo/gfile.h
index 0f02180..5a17773 100644
--- a/goo/gfile.h
+++ b/goo/gfile.h
@@ -146,6 +146,7 @@ public:
   Goffset size() const;
   
   static GooFile *open(const GooString *fileName);
+  static GooFile *open(int fd);
   
 #ifdef _WIN32
   static GooFile *open(const wchar_t *fileName);
@@ -154,7 +155,7 @@ public:
 
   // Asuming than on windows you can't change files that are already open
   bool modificationTimeChangedSinceOpen() const;
-  
+
 private:
   GooFile(HANDLE handleA);
   HANDLE handle;
@@ -163,7 +164,7 @@ private:
   ~GooFile() { close(fd); }
 
   bool modificationTimeChangedSinceOpen() const;
-    
+
 private:
   GooFile(int fdA);
   int fd;
diff --git a/test/gtk-test.cc b/test/gtk-test.cc
index ec8a9eb..d970083 100644
--- a/test/gtk-test.cc
+++ b/test/gtk-test.cc
@@ -20,15 +20,18 @@
 #include <poppler-private.h>
 #include <gtk/gtk.h>
 #include <math.h>
+#include <errno.h>
 
 static int 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, &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…" },
   { }
 };
@@ -377,31 +380,50 @@ main (int argc, char *argv [])
 
   for (int i = 0; file_arguments[i]; i++) {
     View            *view;
-    GFile           *file;
-    PopplerDocument *doc;
+    GFile           *file = nullptr;
+    PopplerDocument *doc = nullptr;
     GError          *error = nullptr;
+    const char      *arg;
 
-    file = g_file_new_for_commandline_arg (file_arguments[i]);
-    doc = poppler_document_new_from_gfile (file, nullptr, nullptr, &error);
-    if (!doc) {
-      gchar *uri;
+    arg = file_arguments[i];
+    if (args_are_fds) {
+      char *end;
+      gint64 v;
 
-      uri = g_file_get_uri (file);
-      g_printerr ("Error opening document %s: %s\n", uri, error->message);
-      g_error_free (error);
-      g_free (uri);
+      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 (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 (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 ();
 
   delete globalParams;
 
-- 
2.9.4


From e80f295f152b444007bcd558dc829fec3e50d83c Mon Sep 17 00:00:00 2001
From: Christian Persch <chpe@src.gnome.org>
Date: Thu, 16 Aug 2018 23:02:58 +0200
Subject: [PATCH 3/3] glib: Add API to save to file descriptor

---
 glib/poppler-attachment.cc          | 76 ++++++++++++++++++++++++++++++++++---
 glib/poppler-attachment.h           |  3 ++
 glib/poppler-document.cc            | 59 ++++++++++++++++++++++++++++
 glib/poppler-document.h             |  8 ++++
 glib/poppler-media.cc               | 74 +++++++++++++++++++++++++++++++++---
 glib/poppler-media.h                |  3 ++
 glib/reference/poppler-sections.txt |  3 ++
 7 files changed, 214 insertions(+), 12 deletions(-)

diff --git a/glib/poppler-attachment.cc b/glib/poppler-attachment.cc
index c6502e9..545ea7a 100644
--- a/glib/poppler-attachment.cc
+++ b/glib/poppler-attachment.cc
@@ -138,11 +138,12 @@ save_helper (const gchar  *buf,
   n = fwrite (buf, 1, count, f);
   if (n != count)
     {
+      int errsv = errno;
       g_set_error (error,
 		   G_FILE_ERROR,
-		   g_file_error_from_errno (errno),
+		   g_file_error_from_errno (errsv),
 		   _("Error writing to image file: %s"),
-		   g_strerror (errno));
+		   g_strerror (errsv));
       return FALSE;
     }
 
@@ -170,18 +171,22 @@ poppler_attachment_save (PopplerAttachment  *attachment,
   FILE *f;
   
   g_return_val_if_fail (POPPLER_IS_ATTACHMENT (attachment), FALSE);
+  g_return_val_if_fail (filename != nullptr, FALSE);
+  g_return_val_if_fail (error == nullptr || *error == nullptr, FALSE);
+
 
   f = g_fopen (filename, "wb");
 
   if (f == nullptr)
     {
+      int errsv = errno;
       gchar *display_name = g_filename_display_name (filename);
       g_set_error (error,
 		   G_FILE_ERROR,
-		   g_file_error_from_errno (errno),
+		   g_file_error_from_errno (errsv),
 		   _("Failed to open '%s' for writing: %s"),
 		   display_name,
-		   g_strerror (errno));
+		   g_strerror (errsv));
       g_free (display_name);
       return FALSE;
     }
@@ -190,13 +195,14 @@ poppler_attachment_save (PopplerAttachment  *attachment,
 
   if (fclose (f) < 0)
     {
+      int errsv = errno;
       gchar *display_name = g_filename_display_name (filename);
       g_set_error (error,
 		   G_FILE_ERROR,
-		   g_file_error_from_errno (errno),
+		   g_file_error_from_errno (errsv),
 		   _("Failed to close '%s', all data may not have been saved: %s"),
 		   display_name,
-		   g_strerror (errno));
+		   g_strerror (errsv));
       g_free (display_name);
       return FALSE;
     }
@@ -204,6 +210,64 @@ poppler_attachment_save (PopplerAttachment  *attachment,
   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 ownership of @fd; you must not operate on it
+ * again, or close it.
+ *
+ * Return value: %TRUE, if the file successfully saved
+ *
+ * Since: 0.68
+ **/
+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 ff8c849..d4366c7 100644
--- a/glib/poppler-attachment.h
+++ b/glib/poppler-attachment.h
@@ -76,6 +76,9 @@ GType     poppler_attachment_get_type         (void) G_GNUC_CONST;
 gboolean  poppler_attachment_save             (PopplerAttachment          *attachment,
 					       const char                 *filename,
 					       GError                    **error);
+gboolean  poppler_attachment_save_to_fd       (PopplerAttachment          *attachment,
+					       int                         fd,
+					       GError                    **error);
 gboolean  poppler_attachment_save_to_callback (PopplerAttachment          *attachment,
 					       PopplerAttachmentSaveFunc   save_func,
 					       gpointer                    user_data,
diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc
index d986452..3d797c5 100644
--- a/glib/poppler-document.cc
+++ b/glib/poppler-document.cc
@@ -549,6 +549,64 @@ poppler_document_save_a_copy (PopplerDocument  *document,
   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 ownership of @fd; you must not operate on it
+ * again, or 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: 0.68
+ **/
+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)
 {
@@ -2890,6 +2948,7 @@ poppler_ps_file_new (PopplerDocument *document, const char *filename,
 	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 aaa13d9..237f8e1 100644
--- a/glib/poppler-document.h
+++ b/glib/poppler-document.h
@@ -193,6 +193,10 @@ gboolean           poppler_document_save                   (PopplerDocument *doc
 gboolean           poppler_document_save_a_copy            (PopplerDocument *document,
 							    const char      *uri,
 							    GError         **error);
+gboolean           poppler_document_save_to_fd             (PopplerDocument *document,
+							    int              fd,
+							    gboolean         include_changes,
+							    GError         **error);
 gboolean           poppler_document_get_id                 (PopplerDocument *document,
 							    gchar          **permanent_id,
 							    gchar          **update_id);
@@ -306,6 +310,10 @@ PopplerPSFile *poppler_ps_file_new            (PopplerDocument *document,
                                                const char      *filename,
                                                int              first_page,
                                                int              n_pages);
+PopplerPSFile *poppler_ps_file_new_fd         (PopplerDocument *document,
+                                               int              fd,
+                                               int              first_page,
+                                               int              n_pages);
 void           poppler_ps_file_set_paper_size (PopplerPSFile   *ps_file,
                                                double           width,
                                                double           height);
diff --git a/glib/poppler-media.cc b/glib/poppler-media.cc
index b7afa9a..62f5f78 100644
--- a/glib/poppler-media.cc
+++ b/glib/poppler-media.cc
@@ -177,11 +177,12 @@ save_helper (const gchar  *buf,
   n = fwrite (buf, 1, count, f);
   if (n != count)
     {
+      int errsv = errno;
       g_set_error (error,
 		   G_FILE_ERROR,
-		   g_file_error_from_errno (errno),
+		   g_file_error_from_errno (errsv),
 		   "Error writing to media file: %s",
-		   g_strerror (errno));
+		   g_strerror (errsv));
       return FALSE;
     }
 
@@ -218,13 +219,14 @@ poppler_media_save (PopplerMedia *poppler_media,
 
   if (f == nullptr)
     {
+      int errsv = errno;
       gchar *display_name = g_filename_display_name (filename);
       g_set_error (error,
 		   G_FILE_ERROR,
-		   g_file_error_from_errno (errno),
+		   g_file_error_from_errno (errsv),
 		   "Failed to open '%s' for writing: %s",
 		   display_name,
-		   g_strerror (errno));
+		   g_strerror (errsv));
       g_free (display_name);
       return FALSE;
     }
@@ -233,13 +235,14 @@ poppler_media_save (PopplerMedia *poppler_media,
 
   if (fclose (f) < 0)
     {
+      int errsv = errno;
       gchar *display_name = g_filename_display_name (filename);
       g_set_error (error,
 		   G_FILE_ERROR,
-		   g_file_error_from_errno (errno),
+		   g_file_error_from_errno (errsv),
 		   "Failed to close '%s', all data may not have been saved: %s",
 		   display_name,
-		   g_strerror (errno));
+		   g_strerror (errsv));
       g_free (display_name);
       return FALSE;
     }
@@ -247,6 +250,65 @@ poppler_media_save (PopplerMedia *poppler_media,
   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 ownership of @fd; you must not operate on it
+ * again, or close it.
+ *
+ * Return value: %TRUE, if the file successfully saved
+ *
+ * Since: 0.68
+ */
+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 292d386..b80b6d1 100644
--- a/glib/poppler-media.h
+++ b/glib/poppler-media.h
@@ -62,6 +62,9 @@ const gchar *poppler_media_get_mime_type    (PopplerMedia        *poppler_media)
 gboolean     poppler_media_save             (PopplerMedia        *poppler_media,
 					     const char          *filename,
 					     GError             **error);
+gboolean     poppler_media_save_to_fd       (PopplerMedia        *poppler_media,
+					     int                  fd,
+					     GError             **error);
 gboolean     poppler_media_save_to_callback (PopplerMedia        *poppler_media,
 					     PopplerMediaSaveFunc save_func,
 					     gpointer             user_data,
diff --git a/glib/reference/poppler-sections.txt b/glib/reference/poppler-sections.txt
index 8fe501c..715a684 100644
--- a/glib/reference/poppler-sections.txt
+++ b/glib/reference/poppler-sections.txt
@@ -130,6 +130,7 @@ poppler_document_new_from_stream
 poppler_document_new_from_gfile
 poppler_document_new_from_fd
 poppler_document_save
+poppler_document_save_to_fd
 poppler_document_save_a_copy
 poppler_document_get_id
 poppler_document_get_pdf_version_string
@@ -280,6 +281,7 @@ poppler_action_movie_operation_get_type
 PopplerAttachment
 PopplerAttachmentSaveFunc
 poppler_attachment_save
+poppler_attachment_save_to_fd
 poppler_attachment_save_to_callback
 
 <SUBSECTION Standard>
@@ -541,6 +543,7 @@ poppler_media_get_filename
 poppler_media_get_mime_type
 poppler_media_is_embedded
 poppler_media_save
+poppler_media_save_to_fd
 poppler_media_save_to_callback
 
 <SUBSECTION Standard>
-- 
2.9.4

