[poppler] 3 commits - glib/poppler-document.cc glib/poppler-document.h glib/reference poppler/Object.h poppler/PDFDoc.cc poppler/PDFDoc.h poppler/XRef.cc poppler/XRef.h

Carlos Garcia Campos carlosgc at kemper.freedesktop.org
Sun Jul 3 09:03:43 UTC 2016


 glib/poppler-document.cc            |  347 ++++++++++++++++++++++++++----------
 glib/poppler-document.h             |   18 +
 glib/reference/poppler-docs.sgml    |    4 
 glib/reference/poppler-sections.txt |    8 
 poppler/Object.h                    |    7 
 poppler/PDFDoc.cc                   |   79 +++++++-
 poppler/PDFDoc.h                    |   41 ++++
 poppler/XRef.cc                     |   39 ++++
 poppler/XRef.h                      |   14 +
 9 files changed, 456 insertions(+), 101 deletions(-)

New commits:
commit 82476b0d6967ce5e61dce4666fe556edd63c16e6
Author: Jakub Kucharski <jakubkucharski97 at gmail.com>
Date:   Mon Jun 6 22:17:57 2016 +0200

    glib: Added document property setters & simplified getters
    
    https://bugs.freedesktop.org/show_bug.cgi?id=36653

diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc
index 61d92e8..63eae7c 100644
--- a/glib/poppler-document.cc
+++ b/glib/poppler-document.cc
@@ -1,6 +1,8 @@
 /* poppler-document.cc: glib wrapper for poppler
  * Copyright (C) 2005, Red Hat, Inc.
  *
+ * Copyright (C) 2016 Jakub Kucharski <jakubkucharski97 at gmail.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
@@ -22,6 +24,7 @@
 #ifndef __GI_SCANNER__
 #include <goo/GooList.h>
 #include <splash/SplashBitmap.h>
+#include <DateInfo.h>
 #include <GlobalParams.h>
 #include <PDFDoc.h>
 #include <Outline.h>
@@ -711,6 +714,10 @@ poppler_document_find_dest (PopplerDocument *document,
 
 char *_poppler_goo_string_to_utf8(GooString *s)
 {
+  if (s == NULL) {
+    return NULL;
+  }
+
   char *result;
 
   if (s->hasUnicodeMarker()) {
@@ -737,40 +744,28 @@ char *_poppler_goo_string_to_utf8(GooString *s)
   return result;
 }
 
-static gchar *
-info_dict_get_string (Dict *info_dict, const gchar *key)
+static GooString *
+_poppler_goo_string_from_utf8(const gchar *src)
 {
-  Object obj;
-  GooString *goo_value;
-  gchar *result;
-
-  if (!info_dict->lookup ((gchar *)key, &obj)->isString ()) {
-    obj.free ();
+  if (src == NULL) {
     return NULL;
   }
 
-  goo_value = obj.getString ();
-  result = _poppler_goo_string_to_utf8(goo_value);
-  obj.free ();
+  gsize outlen;
 
-  return result;
-}
+  gchar *utf16 = g_convert (src, -1, "UTF-16BE", "UTF-8", NULL, &outlen, NULL);
+  if (utf16 == NULL) {
+    return NULL;
+  }
 
-static time_t
-info_dict_get_date (Dict *info_dict, const gchar *key)
-{
-  Object obj;
-  time_t result;
+  GooString *result = new GooString (utf16, outlen);
+  g_free (utf16);
 
-  if (!info_dict->lookup ((gchar *)key, &obj)->isString ()) {
-    obj.free ();
-    return (time_t)-1;
+  if (!result->hasUnicodeMarker()) {
+    result->insert(0, 0xff);
+    result->insert(0, 0xfe);
   }
 
-  if (!_poppler_convert_pdf_date_to_gtime (obj.getString (), &result))
-    result = (time_t)-1;
-  obj.free ();
-
   return result;
 }
 
@@ -879,17 +874,39 @@ poppler_document_get_pdf_version (PopplerDocument *document,
 gchar *
 poppler_document_get_title (PopplerDocument *document)
 {
-  Object obj;
-  gchar *retval = NULL;
-
   g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), NULL);
 
-  document->doc->getDocInfo (&obj);
-  if (obj.isDict ())
-    retval = info_dict_get_string (obj.getDict(), "Title");
-  obj.free ();
+  GooString *goo_title = document->doc->getDocInfoTitle();
+  gchar *utf8 = _poppler_goo_string_to_utf8(goo_title);
+  delete goo_title;
 
-  return retval;
+  return utf8;
+}
+
+/**
+ * poppler_document_set_title:
+ * @document: A #PopplerDocument
+ * @title: A new title
+ *
+ * Sets the document's title. If @title is %NULL, Title entry
+ * is removed from the document's Info dictionary.
+ *
+ * Since: 0.46
+ **/
+void
+poppler_document_set_title (PopplerDocument *document, const gchar *title)
+{
+  g_return_if_fail (POPPLER_IS_DOCUMENT (document));
+
+  GooString *goo_title;
+  if (!title) {
+    goo_title = NULL;
+  } else {
+    goo_title = _poppler_goo_string_from_utf8(title);
+    if (!goo_title)
+      return;
+  }
+  document->doc->setDocInfoTitle(goo_title);
 }
 
 /**
@@ -906,17 +923,39 @@ poppler_document_get_title (PopplerDocument *document)
 gchar *
 poppler_document_get_author (PopplerDocument *document)
 {
-  Object obj;
-  gchar *retval = NULL;
-
   g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), NULL);
 
-  document->doc->getDocInfo (&obj);
-  if (obj.isDict ())
-    retval = info_dict_get_string (obj.getDict(), "Author");
-  obj.free ();
+  GooString *goo_author = document->doc->getDocInfoAuthor();
+  gchar *utf8 = _poppler_goo_string_to_utf8(goo_author);
+  delete goo_author;
 
-  return retval;
+  return utf8;
+}
+
+/**
+ * poppler_document_set_author:
+ * @document: A #PopplerDocument
+ * @author: A new author
+ *
+ * Sets the document's author. If @author is %NULL, Author
+ * entry is removed from the document's Info dictionary.
+ *
+ * Since: 0.46
+ **/
+void
+poppler_document_set_author (PopplerDocument *document, const gchar *author)
+{
+  g_return_if_fail (POPPLER_IS_DOCUMENT (document));
+
+  GooString *goo_author;
+  if (!author) {
+    goo_author = NULL;
+  } else {
+    goo_author = _poppler_goo_string_from_utf8(author);
+    if (!goo_author)
+      return;
+  }
+  document->doc->setDocInfoAuthor(goo_author);
 }
 
 /**
@@ -933,17 +972,39 @@ poppler_document_get_author (PopplerDocument *document)
 gchar *
 poppler_document_get_subject (PopplerDocument *document)
 {
-  Object obj;
-  gchar *retval = NULL;
-
   g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), NULL);
 
-  document->doc->getDocInfo (&obj);
-  if (obj.isDict ())
-    retval = info_dict_get_string (obj.getDict(), "Subject");
-  obj.free ();
+  GooString *goo_subject = document->doc->getDocInfoSubject();
+  gchar *utf8 = _poppler_goo_string_to_utf8(goo_subject);
+  delete goo_subject;
 
-  return retval;
+  return utf8;
+}
+
+/**
+ * poppler_document_set_subject:
+ * @document: A #PopplerDocument
+ * @subject: A new subject
+ *
+ * Sets the document's subject. If @subject is %NULL, Subject
+ * entry is removed from the document's Info dictionary.
+ *
+ * Since: 0.46
+ **/
+void
+poppler_document_set_subject (PopplerDocument *document, const gchar *subject)
+{
+  g_return_if_fail (POPPLER_IS_DOCUMENT (document));
+
+  GooString *goo_subject;
+  if (!subject) {
+    goo_subject = NULL;
+  } else {
+    goo_subject = _poppler_goo_string_from_utf8(subject);
+    if (!goo_subject)
+      return;
+  }
+  document->doc->setDocInfoSubject(goo_subject);
 }
 
 /**
@@ -960,17 +1021,39 @@ poppler_document_get_subject (PopplerDocument *document)
 gchar *
 poppler_document_get_keywords (PopplerDocument *document)
 {
-  Object obj;
-  gchar *retval = NULL;
-
   g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), NULL);
 
-  document->doc->getDocInfo (&obj);
-  if (obj.isDict ())
-    retval = info_dict_get_string (obj.getDict(), "Keywords");
-  obj.free ();
+  GooString *goo_keywords = document->doc->getDocInfoKeywords();
+  gchar *utf8 = _poppler_goo_string_to_utf8(goo_keywords);
+  delete goo_keywords;
 
-  return retval;
+  return utf8;
+}
+
+/**
+ * poppler_document_set_keywords:
+ * @document: A #PopplerDocument
+ * @keywords: New keywords
+ *
+ * Sets the document's keywords. If @keywords is %NULL,
+ * Keywords entry is removed from the document's Info dictionary.
+ *
+ * Since: 0.46
+ **/
+void
+poppler_document_set_keywords (PopplerDocument *document, const gchar *keywords)
+{
+  g_return_if_fail (POPPLER_IS_DOCUMENT (document));
+
+  GooString *goo_keywords;
+  if (!keywords) {
+    goo_keywords = NULL;
+  } else {
+    goo_keywords = _poppler_goo_string_from_utf8(keywords);
+    if (!goo_keywords)
+      return;
+  }
+  document->doc->setDocInfoKeywords(goo_keywords);
 }
 
 /**
@@ -989,17 +1072,39 @@ poppler_document_get_keywords (PopplerDocument *document)
 gchar *
 poppler_document_get_creator (PopplerDocument *document)
 {
-  Object obj;
-  gchar *retval = NULL;
-
   g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), NULL);
 
-  document->doc->getDocInfo (&obj);
-  if (obj.isDict ())
-    retval = info_dict_get_string (obj.getDict(), "Creator");
-  obj.free ();
+  GooString *goo_creator = document->doc->getDocInfoCreator();
+  gchar *utf8 = _poppler_goo_string_to_utf8(goo_creator);
+  delete goo_creator;
 
-  return retval;
+  return utf8;
+}
+
+/**
+ * poppler_document_set_creator:
+ * @document: A #PopplerDocument
+ * @creator: A new creator
+ *
+ * Sets the document's creator. If @creator is %NULL, Creator
+ * entry is removed from the document's Info dictionary.
+ *
+ * Since: 0.46
+ **/
+void
+poppler_document_set_creator (PopplerDocument *document, const gchar *creator)
+{
+  g_return_if_fail (POPPLER_IS_DOCUMENT (document));
+
+  GooString *goo_creator;
+  if (!creator) {
+    goo_creator = NULL;
+  } else {
+    goo_creator = _poppler_goo_string_from_utf8(creator);
+    if (!goo_creator)
+      return;
+  }
+  document->doc->setDocInfoCreator(goo_creator);
 }
 
 /**
@@ -1018,17 +1123,39 @@ poppler_document_get_creator (PopplerDocument *document)
 gchar *
 poppler_document_get_producer (PopplerDocument *document)
 {
-  Object obj;
-  gchar *retval = NULL;
-
   g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), NULL);
 
-  document->doc->getDocInfo (&obj);
-  if (obj.isDict ())
-    retval = info_dict_get_string (obj.getDict(), "Producer");
-  obj.free ();
+  GooString *goo_producer = document->doc->getDocInfoProducer();
+  gchar *utf8 = _poppler_goo_string_to_utf8(goo_producer);
+  delete goo_producer;
 
-  return retval;
+  return utf8;
+}
+
+/**
+ * poppler_document_set_producer:
+ * @document: A #PopplerDocument
+ * @producer: A new producer
+ *
+ * Sets the document's producer. If @producer is %NULL,
+ * Producer entry is removed from the document's Info dictionary.
+ *
+ * Since: 0.46
+ **/
+void
+poppler_document_set_producer (PopplerDocument *document, const gchar *producer)
+{
+  g_return_if_fail (POPPLER_IS_DOCUMENT (document));
+
+  GooString *goo_producer;
+  if (!producer) {
+    goo_producer = NULL;
+  } else {
+    goo_producer = _poppler_goo_string_from_utf8(producer);
+    if (!goo_producer)
+      return;
+  }
+  document->doc->setDocInfoProducer(goo_producer);
 }
 
 /**
@@ -1044,17 +1171,38 @@ poppler_document_get_producer (PopplerDocument *document)
 time_t
 poppler_document_get_creation_date (PopplerDocument *document)
 {
-  Object obj;
-  time_t retval = (time_t)-1;
-
   g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), (time_t)-1);
 
-  document->doc->getDocInfo (&obj);
-  if (obj.isDict ())
-    retval = info_dict_get_date (obj.getDict(), "CreationDate");
-  obj.free ();
+  GooString *str = document->doc->getDocInfoCreatDate();
+  if (str == NULL) {
+    return (time_t)-1;
+  }
 
-  return retval;
+  time_t date;
+  gboolean success = _poppler_convert_pdf_date_to_gtime (str, &date);
+  delete str;
+
+  return (success) ? date : (time_t)-1;
+}
+
+/**
+ * poppler_document_set_creation_date:
+ * @document: A #PopplerDocument
+ * @creation_date: A new creation date
+ *
+ * Sets the document's creation date. If @creation_date is -1, CreationDate
+ * entry is removed from the document's Info dictionary.
+ *
+ * Since: 0.46
+ **/
+void
+poppler_document_set_creation_date (PopplerDocument *document,
+                                    time_t creation_date)
+{
+  g_return_if_fail (POPPLER_IS_DOCUMENT (document));
+
+  GooString *str = creation_date == (time_t)-1 ? NULL : timeToDateString (&creation_date);
+  document->doc->setDocInfoCreatDate (str);
 }
 
 /**
@@ -1070,17 +1218,38 @@ poppler_document_get_creation_date (PopplerDocument *document)
 time_t
 poppler_document_get_modification_date (PopplerDocument *document)
 {
-  Object obj;
-  time_t retval = (time_t)-1;
-
   g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), (time_t)-1);
 
-  document->doc->getDocInfo (&obj);
-  if (obj.isDict ())
-    retval = info_dict_get_date (obj.getDict(), "ModDate");
-  obj.free ();
+  GooString *str = document->doc->getDocInfoModDate();
+  if (str == NULL) {
+    return (time_t)-1;
+  }
+
+  time_t date;
+  gboolean success = _poppler_convert_pdf_date_to_gtime (str, &date);
+  delete str;
 
-  return retval;
+  return (success) ? date : (time_t)-1;
+}
+
+/**
+ * poppler_document_set_modification_date:
+ * @document: A #PopplerDocument
+ * @modification_date: A new modification date
+ *
+ * Sets the document's modification date. If @modification_date is -1, ModDate
+ * entry is removed from the document's Info dictionary.
+ *
+ * Since: 0.46
+ **/
+void
+poppler_document_set_modification_date (PopplerDocument *document,
+                                        time_t modification_date)
+{
+  g_return_if_fail (POPPLER_IS_DOCUMENT (document));
+
+  GooString *str = modification_date == (time_t)-1 ? NULL : timeToDateString (&modification_date);
+  document->doc->setDocInfoModDate (str);
 }
 
 /**
diff --git a/glib/poppler-document.h b/glib/poppler-document.h
index a34e88c..fb0ac72 100644
--- a/glib/poppler-document.h
+++ b/glib/poppler-document.h
@@ -1,6 +1,8 @@
 /* poppler-document.h: glib interface to poppler
  * Copyright (C) 2004, Red Hat, Inc.
  *
+ * Copyright (C) 2016 Jakub Kucharski <jakubkucharski97 at gmail.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
@@ -201,13 +203,29 @@ void               poppler_document_get_pdf_version        (PopplerDocument *doc
 							    guint           *major_version,
 							    guint           *minor_version);
 gchar             *poppler_document_get_title              (PopplerDocument *document);
+void               poppler_document_set_title              (PopplerDocument *document,
+							    const gchar     *title);
 gchar             *poppler_document_get_author             (PopplerDocument *document);
+void               poppler_document_set_author             (PopplerDocument *document,
+							    const gchar     *author);
 gchar             *poppler_document_get_subject            (PopplerDocument *document);
+void               poppler_document_set_subject            (PopplerDocument *document,
+							    const gchar     *subject);
 gchar             *poppler_document_get_keywords           (PopplerDocument *document);
+void               poppler_document_set_keywords           (PopplerDocument *document,
+                                                            const gchar     *keywords);
 gchar             *poppler_document_get_creator            (PopplerDocument *document);
+void               poppler_document_set_creator            (PopplerDocument *document,
+                                                            const gchar     *creator);
 gchar             *poppler_document_get_producer           (PopplerDocument *document);
+void               poppler_document_set_producer           (PopplerDocument *document,
+                                                            const gchar     *producer);
 time_t             poppler_document_get_creation_date      (PopplerDocument *document);
+void               poppler_document_set_creation_date      (PopplerDocument *document,
+                                                            time_t           creation_date);
 time_t             poppler_document_get_modification_date  (PopplerDocument *document);
+void               poppler_document_set_modification_date  (PopplerDocument *document,
+                                                            time_t           modification_date);
 gboolean           poppler_document_is_linearized          (PopplerDocument *document);
 PopplerPageLayout  poppler_document_get_page_layout        (PopplerDocument *document);
 PopplerPageMode    poppler_document_get_page_mode          (PopplerDocument *document);
diff --git a/glib/reference/poppler-docs.sgml b/glib/reference/poppler-docs.sgml
index ec8a3eb..5db818f 100644
--- a/glib/reference/poppler-docs.sgml
+++ b/glib/reference/poppler-docs.sgml
@@ -69,6 +69,10 @@
     <title>Index of new symbols in 0.33</title>
     <xi:include href="xml/api-index-0.33.xml"><xi:fallback /></xi:include>
   </index>
+  <index id="api-index-0-46">
+    <title>Index of new symbols in 0.46</title>
+    <xi:include href="xml/api-index-0.46.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 92bf432..d597c2d 100644
--- a/glib/reference/poppler-sections.txt
+++ b/glib/reference/poppler-sections.txt
@@ -134,13 +134,21 @@ poppler_document_get_id
 poppler_document_get_pdf_version_string
 poppler_document_get_pdf_version
 poppler_document_get_title
+poppler_document_set_title
 poppler_document_get_author
+poppler_document_set_author
 poppler_document_get_subject
+poppler_document_set_subject
 poppler_document_get_keywords
+poppler_document_set_keywords
 poppler_document_get_creator
+poppler_document_set_creator
 poppler_document_get_producer
+poppler_document_set_producer
 poppler_document_get_creation_date
+poppler_document_set_creation_date
 poppler_document_get_modification_date
+poppler_document_set_modification_date
 poppler_document_get_page_layout
 poppler_document_get_page_mode
 poppler_document_get_permissions
commit 4f7c67b59b9c55b9b896378d3adbecbb73f6eb63
Author: Jakub Kucharski <jakubkucharski97 at gmail.com>
Date:   Tue Feb 23 16:46:43 2016 +0100

    Added DocInfo setters & getters
    
    https://bugs.freedesktop.org/show_bug.cgi?id=36653

diff --git a/poppler/Object.h b/poppler/Object.h
index b9cae28..0c7767c 100644
--- a/poppler/Object.h
+++ b/poppler/Object.h
@@ -21,6 +21,7 @@
 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2013 Adrian Johnson <ajohnson at redneon.com>
 // Copyright (C) 2013 Adrian Perez de Castro <aperez at igalia.com>
+// Copyright (C) 2016 Jakub Kucharski <jakubkucharski97 at gmail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -235,6 +236,7 @@ public:
   int dictGetLength();
   void dictAdd(char *key, Object *val);
   void dictSet(const char *key, Object *val);
+  void dictRemove(const char *key);
   GBool dictIs(const char *dictType);
   Object *dictLookup(const char *key, Object *obj, int recursion = 0);
   Object *dictLookupNF(const char *key, Object *obj);
@@ -318,7 +320,10 @@ inline void Object::dictAdd(char *key, Object *val)
   { OBJECT_TYPE_CHECK(objDict); dict->add(key, val); }
 
 inline void Object::dictSet(const char *key, Object *val)
- 	{ OBJECT_TYPE_CHECK(objDict); dict->set(key, val); }
+  { OBJECT_TYPE_CHECK(objDict); dict->set(key, val); }
+
+inline void Object::dictRemove(const char *key)
+  { OBJECT_TYPE_CHECK(objDict); dict->remove(key); }
 
 inline GBool Object::dictIs(const char *dictType)
   { OBJECT_TYPE_CHECK(objDict); return dict->is(dictType); }
diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index 703a4fd..c91d6e4 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -34,6 +34,7 @@
 // Copyright (C) 2015 Li Junling <lijunling at sina.com>
 // Copyright (C) 2015 André Guerreiro <aguerreiro1985 at gmail.com>
 // Copyright (C) 2015 André Esser <bepandre at hotmail.com>
+// Copyright (C) 2016 Jakub Kucharski <jakubkucharski97 at gmail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -600,6 +601,72 @@ GBool PDFDoc::isLinearized(GBool tryingToReconstruct) {
   }
 }
 
+void PDFDoc::setDocInfoModified(Object *infoObj)
+{
+  Object infoObjRef;
+  getDocInfoNF(&infoObjRef);
+  xref->setModifiedObject(infoObj, infoObjRef.getRef());
+  infoObjRef.free();
+}
+
+void PDFDoc::setDocInfoStringEntry(const char *key, GooString *value)
+{
+  GBool removeEntry = !value || value->getLength() == 0;
+
+  Object infoObj;
+  getDocInfo(&infoObj);
+
+  if (infoObj.isNull() && removeEntry) {
+    // No info dictionary, so no entry to remove.
+    return;
+  }
+
+  createDocInfoIfNoneExists(&infoObj);
+
+  Object gooStrObj;
+  if (removeEntry) {
+    gooStrObj.initNull();
+  } else {
+    gooStrObj.initString(value);
+  }
+
+  // gooStrObj is set to value or null by now. The latter will cause a removal.
+  infoObj.dictSet(key, &gooStrObj);
+
+  if (infoObj.dictGetLength() == 0) {
+    // Info dictionary is empty. Remove it altogether.
+    removeDocInfo();
+  } else {
+    setDocInfoModified(&infoObj);
+  }
+
+  infoObj.free();
+}
+
+GooString *PDFDoc::getDocInfoStringEntry(const char *key) {
+  Object infoObj;
+  getDocInfo(&infoObj);
+  if (infoObj.isNull()) {
+      return NULL;
+  }
+
+  Object entryObj;
+  infoObj.dictLookup(key, &entryObj);
+
+  GooString *result;
+
+  if (entryObj.isString()) {
+    result = entryObj.takeString();
+  } else {
+    result = NULL;
+  }
+
+  entryObj.free();
+  infoObj.free();
+
+  return result;
+}
+
 static GBool
 get_id (GooString *encodedidstring, GooString *id) {
   const char *encodedid = encodedidstring->getCString();
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index 3a65ecb..daff3f4 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -29,6 +29,7 @@
 // Copyright (C) 2013 Adrian Perez de Castro <aperez at igalia.com>
 // Copyright (C) 2015 André Guerreiro <aguerreiro1985 at gmail.com>
 // Copyright (C) 2015 André Esser <bepandre at hotmail.com>
+// Copyright (C) 2016 Jakub Kucharski <jakubkucharski97 at gmail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -231,6 +232,43 @@ public:
   Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); }
   Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); }
 
+  // Create and return the document's Info dictionary if none exists.
+  // Otherwise return the existing one.
+  Object *createDocInfoIfNoneExists(Object *obj) { return xref->createDocInfoIfNoneExists(obj); }
+
+  // Remove the document's Info dictionary and update the trailer dictionary.
+  void removeDocInfo() { xref->removeDocInfo(); }
+
+  // Set doc info string entry. NULL or empty value will cause a removal.
+  // Takes ownership of value.
+  void setDocInfoStringEntry(const char *key, GooString *value);
+
+  // Set document's properties in document's Info dictionary.
+  // NULL or empty value will cause a removal.
+  // Takes ownership of value.
+  void setDocInfoTitle(GooString *title) { setDocInfoStringEntry("Title", title); }
+  void setDocInfoAuthor(GooString *author) { setDocInfoStringEntry("Author", author); }
+  void setDocInfoSubject(GooString *subject) { setDocInfoStringEntry("Subject", subject); }
+  void setDocInfoKeywords(GooString *keywords) { setDocInfoStringEntry("Keywords", keywords); }
+  void setDocInfoCreator(GooString *creator) { setDocInfoStringEntry("Creator", creator); }
+  void setDocInfoProducer(GooString *producer) { setDocInfoStringEntry("Producer", producer); }
+  void setDocInfoCreatDate(GooString *creatDate) { setDocInfoStringEntry("CreationDate", creatDate); }
+  void setDocInfoModDate(GooString *modDate) { setDocInfoStringEntry("ModDate", modDate); }
+
+  // Get document's properties from document's Info dictionary.
+  // Returns NULL on fail.
+  // Returned GooStrings should be freed by the caller.
+  GooString *getDocInfoStringEntry(const char *key);
+
+  GooString *getDocInfoTitle() { return getDocInfoStringEntry("Title"); }
+  GooString *getDocInfoAuthor() { return getDocInfoStringEntry("Author"); }
+  GooString *getDocInfoSubject() { return getDocInfoStringEntry("Subject"); }
+  GooString *getDocInfoKeywords() { return getDocInfoStringEntry("Keywords"); }
+  GooString *getDocInfoCreator() { return getDocInfoStringEntry("Creator"); }
+  GooString *getDocInfoProducer() { return getDocInfoStringEntry("Producer"); }
+  GooString *getDocInfoCreatDate() { return getDocInfoStringEntry("CreationDate"); }
+  GooString *getDocInfoModDate() { return getDocInfoStringEntry("ModDate"); }
+
   // Return the PDF version specified by the file.
   int getPDFMajorVersion() { return pdfMajorVersion; }
   int getPDFMinorVersion() { return pdfMinorVersion; }
@@ -315,6 +353,9 @@ private:
   Goffset getMainXRefEntriesOffset(GBool tryingToReconstruct = gFalse);
   long long strToLongLong(char *s);
 
+  // Mark the document's Info dictionary as modified.
+  void setDocInfoModified(Object *infoObj);
+
   GooString *fileName;
 #ifdef _WIN32
   wchar_t *fileNameU;
diff --git a/poppler/XRef.cc b/poppler/XRef.cc
index 8570819..f88c632 100644
--- a/poppler/XRef.cc
+++ b/poppler/XRef.cc
@@ -1292,6 +1292,40 @@ Object *XRef::getDocInfoNF(Object *obj) {
   return trailerDict.dictLookupNF("Info", obj);
 }
 
+Object *XRef::createDocInfoIfNoneExists(Object *obj) {
+  getDocInfo(obj);
+
+  if (!obj->isNull()) {
+    return obj;
+  }
+
+  obj->initDict(this);
+
+  Ref ref = addIndirectObject(obj);
+
+  Object objRef;
+  objRef.initRef(ref.num, ref.gen);
+
+  trailerDict.dictSet("Info", &objRef);
+
+  objRef.free();
+
+  return obj;
+}
+
+void XRef::removeDocInfo() {
+  Object infoObjRef;
+  getDocInfoNF(&infoObjRef);
+  if (infoObjRef.isNull()) {
+    return;
+  }
+
+  trailerDict.dictRemove("Info");
+
+  removeIndirectObject(infoObjRef.getRef());
+  infoObjRef.free();
+}
+
 GBool XRef::getStreamEnd(Goffset streamStart, Goffset *streamEnd) {
   int a, b, m;
 
diff --git a/poppler/XRef.h b/poppler/XRef.h
index 739b537..245b14b 100644
--- a/poppler/XRef.h
+++ b/poppler/XRef.h
@@ -150,6 +150,13 @@ public:
   Object *getDocInfo(Object *obj);
   Object *getDocInfoNF(Object *obj);
 
+  // Create and return the document's Info dictionary if none exists.
+  // Otherwise return the existing one.
+  Object *createDocInfoIfNoneExists(Object *obj);
+
+  // Remove the document's Info dictionary and update the trailer dictionary.
+  void removeDocInfo();
+
   // Return the number of objects in the xref table.
   int getNumObjects() { return size; }
 
commit e2851dd8166fa5a1df0518959ad71c9d81bd9152
Author: Jakub Kucharski <jakubkucharski97 at gmail.com>
Date:   Tue Feb 23 15:36:43 2016 +0100

    Added XRef modification flag
    
    https://bugs.freedesktop.org/show_bug.cgi?id=36653

diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index 9fc43e5..703a4fd 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -865,17 +865,7 @@ int PDFDoc::saveAs(GooString *name, PDFWriteMode mode) {
 }
 
 int PDFDoc::saveAs(OutStream *outStr, PDFWriteMode mode) {
-
-  // find if we have updated objects
-  GBool updated = gFalse;
-  for(int i=0; i<xref->getNumObjects(); i++) {
-    if (xref->getEntry(i)->getFlag(XRefEntry::Updated)) {
-      updated = gTrue;
-      break;
-    }
-  }
-
-  if (!updated && mode == writeStandard) {
+  if (!xref->isModified() && mode == writeStandard) {
     // simply copy the original file
     saveWithoutChangesAs (outStr);
   } else if (mode == writeForceRewrite) {
diff --git a/poppler/XRef.cc b/poppler/XRef.cc
index 3d032bc..8570819 100644
--- a/poppler/XRef.cc
+++ b/poppler/XRef.cc
@@ -24,6 +24,7 @@
 // Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso at hotmail.it>
 // Copyright (C) 2013, 2014 Adrian Johnson <ajohnson at redneon.com>
 // Copyright (C) 2013 Pino Toscano <pino at kde.org>
+// Copyright (C) 2016 Jakub Kucharski <jakubkucharski97 at gmail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -286,6 +287,7 @@ void XRef::init() {
   entries = NULL;
   capacity = 0;
   size = 0;
+  modified = gFalse;
   streamEnds = NULL;
   streamEndsLen = 0;
   objStrs = new PopplerCache(5);
@@ -1373,6 +1375,7 @@ void XRef::setModifiedObject (Object* o, Ref r) {
   e->obj.free();
   o->copy(&(e->obj));
   e->setFlag(XRefEntry::Updated, gTrue);
+  setModified();
 }
 
 Ref XRef::addIndirectObject (Object* o) {
@@ -1398,6 +1401,7 @@ Ref XRef::addIndirectObject (Object* o) {
   e->type = xrefEntryUncompressed;
   o->copy(&e->obj);
   e->setFlag(XRefEntry::Updated, gTrue);
+  setModified();
 
   Ref r;
   r.num = entryIndexToUse;
@@ -1419,6 +1423,7 @@ void XRef::removeIndirectObject(Ref r) {
   e->type = xrefEntryFree;
   e->gen++;
   e->setFlag(XRefEntry::Updated, gTrue);
+  setModified();
 }
 
 void XRef::writeXRef(XRef::XRefWriter *writer, GBool writeAllEntries) {
diff --git a/poppler/XRef.h b/poppler/XRef.h
index 8748cb4..739b537 100644
--- a/poppler/XRef.h
+++ b/poppler/XRef.h
@@ -22,6 +22,7 @@
 // Copyright (C) 2012, 2013, 2016 Thomas Freitag <Thomas.Freitag at kabelmail.de>
 // Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso at hotmail.it>
 // Copyright (C) 2013 Adrian Johnson <ajohnson at redneon.com>
+// Copyright (C) 2016 Jakub Kucharski <jakubkucharski97 at gmail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -175,6 +176,11 @@ public:
   XRefEntry *getEntry(int i, GBool complainIfMissing = gTrue);
   Object *getTrailerDict() { return &trailerDict; }
 
+  // Was the XRef modified?
+  GBool isModified() { return modified; }
+  // Set the modification flag for XRef to true.
+  void setModified() { modified = gTrue; }
+
   // Write access
   void setModifiedObject(Object* o, Ref r);
   Ref addIndirectObject (Object* o);
@@ -203,6 +209,7 @@ private:
   int errCode;			// error code (if <ok> is false)
   GBool xrefReconstructed;	// marker, true if xref was already reconstructed
   Object trailerDict;		// trailer dictionary
+  GBool modified;
   Goffset *streamEnds;		// 'endstream' positions - only used in
 				//   damaged files
   int streamEndsLen;		// number of valid entries in streamEnds


More information about the poppler mailing list