From baa49aa56b8a96b07ab2a9bb901f5347eb4518fc Mon Sep 17 00:00:00 2001 From: Jakub Kucharski Date: Fri, 29 Jan 2016 00:37:19 +0100 Subject: [PATCH] Implement functions for modifying PDFDoc Info dictionary --- poppler/Object.h | 6 ++++- poppler/PDFDoc.cc | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- poppler/PDFDoc.h | 12 ++++++++++ poppler/XRef.cc | 1 + poppler/XRef.h | 6 +++++ 5 files changed, 93 insertions(+), 4 deletions(-) diff --git a/poppler/Object.h b/poppler/Object.h index 1b06a3c..ffcc00c 100644 --- a/poppler/Object.h +++ b/poppler/Object.h @@ -225,6 +225,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); @@ -308,7 +309,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 46c4544..5f708ce 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -537,6 +537,73 @@ GBool PDFDoc::isLinearized(GBool tryingToReconstruct) { } } +void PDFDoc::setInfoDictModified(Object *infoObj) +{ + Object infoObjRef; + getDocInfoNF(&infoObjRef); + xref->setModifiedObject(infoObj, infoObjRef.getRef()); + infoObjRef.free(); +} + +void PDFDoc::createInfoDictIfNoneExists(Object *infoObj) { + Object origInfoObjRef; + getDocInfoNF(&origInfoObjRef); + + if (origInfoObjRef.isNull()) { + infoObj->initDict(xref); + + Ref infoRef = xref->addIndirectObject(infoObj); + Object infoObjRef; + infoObjRef.initRef(infoRef.num, infoRef.gen); + + xref->getTrailerDict()->dictSet("Info", &infoObjRef); + infoObjRef.free(); + + xref->setTrailerDictModified(); + } + + origInfoObjRef.free(); +} + +void PDFDoc::setDocInfoStringEntry(const char *key, GooString *value) +{ + Object infoObj; + getDocInfo(&infoObj); + createInfoDictIfNoneExists(&infoObj); + + Object gooStrObj; + gooStrObj.initNull(); + + if (value && value->getLength() != 0) { + 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 { + setInfoDictModified(&infoObj); + } + + infoObj.free(); +} + +void PDFDoc::removeDocInfo() +{ + Object infoObjRef; + getDocInfoNF(&infoObjRef); + + Object * trailerDict = xref->getTrailerDict(); + trailerDict->dictRemove("Info"); + xref->setTrailerDictModified(); + + xref->removeIndirectObject(infoObjRef.getRef()); + infoObjRef.free(); +} + static GBool get_id (GooString *encodedidstring, GooString *id) { const char *encodedid = encodedidstring->getCString(); @@ -797,11 +864,10 @@ 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; igetNumObjects(); i++) { + GBool updated = xref->isTrailerDictModified(); + for(int i=0; !updated && igetNumObjects(); i++) { if (xref->getEntry(i)->getFlag(XRefEntry::Updated)) { updated = gTrue; - break; } } diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h index 6c40f7b..bbe031c 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -225,6 +225,13 @@ public: Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); } Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); } + // Remove the document's Info dictionary and update the trailer dictionary. + void 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); + // Return the PDF version specified by the file. int getPDFMajorVersion() { return pdfMajorVersion; } int getPDFMinorVersion() { return pdfMinorVersion; } @@ -309,6 +316,11 @@ private: Goffset getMainXRefEntriesOffset(GBool tryingToReconstruct = gFalse); long long strToLongLong(char *s); + // Mark the document's Info dictionary as modified. + void setInfoDictModified(Object *infoObj); + // Create the document's Info dictionary if it doesn't exist yet. + void createInfoDictIfNoneExists(Object *infoObj); + GooString *fileName; #ifdef _WIN32 wchar_t *fileNameU; diff --git a/poppler/XRef.cc b/poppler/XRef.cc index 1bbbdc5..d59b3ea 100644 --- a/poppler/XRef.cc +++ b/poppler/XRef.cc @@ -286,6 +286,7 @@ void XRef::init() { entries = NULL; capacity = 0; size = 0; + trailerDictModified = gFalse; streamEnds = NULL; streamEndsLen = 0; objStrs = new PopplerCache(5); diff --git a/poppler/XRef.h b/poppler/XRef.h index 70065d8..ce264c5 100644 --- a/poppler/XRef.h +++ b/poppler/XRef.h @@ -175,6 +175,11 @@ public: XRefEntry *getEntry(int i, GBool complainIfMissing = gTrue); Object *getTrailerDict() { return &trailerDict; } + // Was the document's trailer dictionary modified? + GBool isTrailerDictModified() { return trailerDictModified; } + // Set the modification flag for the document's trailer dictionary true. + void setTrailerDictModified() { trailerDictModified = gTrue; } + // Write access void setModifiedObject(Object* o, Ref r); Ref addIndirectObject (Object* o); @@ -202,6 +207,7 @@ private: GBool ok; // true if xref table is valid int errCode; // error code (if is false) Object trailerDict; // trailer dictionary + GBool trailerDictModified; Goffset *streamEnds; // 'endstream' positions - only used in // damaged files int streamEndsLen; // number of valid entries in streamEnds -- 2.7.0