From f638210cc3fb246d4c96532a028cc349ff42c9fc Mon Sep 17 00:00:00 2001 From: Jakub Kucharski Date: Tue, 23 Feb 2016 16:46:43 +0100 Subject: [PATCH 2/7] Added DocInfo setters & getters --- poppler/Object.h | 7 +++++- poppler/PDFDoc.cc | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ poppler/PDFDoc.h | 42 ++++++++++++++++++++++++++++++++++++ poppler/XRef.cc | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ poppler/XRef.h | 8 +++++++ 5 files changed, 178 insertions(+), 1 deletion(-) 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 // Copyright (C) 2013 Adrian Johnson // Copyright (C) 2013 Adrian Perez de Castro +// Copyright (C) 2016 Jakub Kucharski // // 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..045dd2a 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -34,6 +34,7 @@ // Copyright (C) 2015 Li Junling // Copyright (C) 2015 André Guerreiro // Copyright (C) 2015 André Esser +// Copyright (C) 2016 Jakub Kucharski // // 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,69 @@ 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); + + Object entryObj; + infoObj.dictLookup(key, &entryObj); + + GooString *result; + + if (entryObj.isString()) { + result = new GooString(entryObj.getString()); + } 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..5069995 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -29,6 +29,7 @@ // Copyright (C) 2013 Adrian Perez de Castro // Copyright (C) 2015 André Guerreiro // Copyright (C) 2015 André Esser +// Copyright (C) 2016 Jakub Kucharski // // 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,44 @@ 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); } + Object *createDocInfoIfNoneExistsNF(Object *obj) { return xref->createDocInfoIfNoneExistsNF(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 +354,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 2515311..4e6ce72 100644 --- a/poppler/XRef.cc +++ b/poppler/XRef.cc @@ -1292,6 +1292,64 @@ 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); + setModified(); + + objRef.free(); + + return obj; +} + +Object *XRef::createDocInfoIfNoneExistsNF(Object *obj) { + getDocInfoNF(obj); + + if (!obj->isNull()) { + return obj; + } + + Object infoObj; + infoObj.initDict(this); + + Ref ref = addIndirectObject(&infoObj); + infoObj.free(); + + Object objRef; + objRef.initRef(ref.num, ref.gen); + + trailerDict.dictSet("Info", &objRef); + setModified(); + + *obj = objRef; + objRef.free(); + + return obj; +} + +void XRef::removeDocInfo() { + Object infoObjRef; + getDocInfoNF(&infoObjRef); + + trailerDict.dictRemove("Info"); + setModified(); + + 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..c608061 100644 --- a/poppler/XRef.h +++ b/poppler/XRef.h @@ -150,6 +150,14 @@ 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); + Object *createDocInfoIfNoneExistsNF(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; } -- 2.8.3