Hello, the attached patch adds an option to strip the encryption from a document by doing a complete rewrite but ignoring the original encryption parameters and removing the encryption entry form the trailer dictionary. It also exposes this via the two Qt frontends.
This might be useful for a separate command-line utility but for now my primary use case is submitting a rewritten but unencrypted document to CUPS for printing instead of converting to PostScript. Best regards, Adam.
From f5097e06dc32414ad041b1c1d54fabb29a6356e9 Mon Sep 17 00:00:00 2001 From: Adam Reichold <[email protected]> Date: Sat, 25 Jul 2015 14:06:46 +0200 Subject: [PATCH 1/2] Add option to strip encryption Adds a PDF write mode that forces a complete rewrite that ignores the original encryption parameters of the document and also removes the encryption entry from the trailer dictionary. --- poppler/PDFDoc.cc | 31 ++++++++++++++++++------------- poppler/PDFDoc.h | 9 +++++---- utils/pdfunite.cc | 2 +- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index 71a1efe..c2c58c2 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -763,7 +763,7 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) Ref ref; ref.num = rootNum; ref.gen = 0; - Dict *trailerDict = createTrailerDict(rootNum + 3, gFalse, 0, &ref, getXRef(), + Dict *trailerDict = createTrailerDict(rootNum + 3, gFalse, gFalse, 0, &ref, getXRef(), name->getCString(), uxrefOffset); writeXRefTableTrailer(trailerDict, yRef, gFalse /* do not write unnecessary entries */, uxrefOffset, outStr, getXRef()); @@ -809,7 +809,10 @@ int PDFDoc::saveAs(OutStream *outStr, PDFWriteMode mode) { // simply copy the original file saveWithoutChangesAs (outStr); } else if (mode == writeForceRewrite) { - saveCompleteRewrite(outStr); + saveCompleteRewrite(outStr, false); + } else if (mode == writeStripEncryption) { + // do a complete rewrite ignoring the original encryption parameters + saveCompleteRewrite(outStr, true); } else { saveIncrementalUpdate(outStr); } @@ -916,7 +919,7 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) uxref->add(uxrefStreamRef.num, uxrefStreamRef.gen, uxrefOffset, gTrue); } - Dict *trailerDict = createTrailerDict(numobjects, gTrue, getStartXRef(), &rootRef, getXRef(), fileNameA, uxrefOffset); + Dict *trailerDict = createTrailerDict(numobjects, gTrue, gFalse, getStartXRef(), &rootRef, getXRef(), fileNameA, uxrefOffset); if (xRefStream) { writeXRefStreamTrailer(trailerDict, uxref, &uxrefStreamRef, uxrefOffset, outStr, getXRef()); } else { @@ -927,16 +930,18 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) delete uxref; } -void PDFDoc::saveCompleteRewrite (OutStream* outStr) +void PDFDoc::saveCompleteRewrite (OutStream* outStr, GBool stripEncryption) { // Make sure that special flags are set, because we are going to read // all objects, including Unencrypted ones. xref->scanSpecialFlags(); - Guchar *fileKey; - CryptAlgorithm encAlgorithm; - int keyLength; - xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); + Guchar *fileKey = NULL; + CryptAlgorithm encAlgorithm = cryptRC4; + int keyLength = 0; + + if (!stripEncryption) + xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); outStr->printf("%%PDF-%d.%d\r\n",pdfMajorVersion,pdfMinorVersion); XRef *uxref = new XRef(); @@ -986,7 +991,7 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr) xref->unlock(); Goffset uxrefOffset = outStr->getPos(); writeXRefTableTrailer(uxrefOffset, uxref, gTrue /* write all entries */, - uxref->getNumObjects(), outStr, gFalse /* complete rewrite */); + uxref->getNumObjects(), outStr, gFalse /* complete rewrite */, stripEncryption); delete uxref; } @@ -1269,7 +1274,7 @@ void PDFDoc::writeObjectFooter (OutStream* outStr) outStr->printf("endobj\r\n"); } -Dict *PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Goffset startxRef, +Dict *PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, GBool stripEncryption, Goffset startxRef, Ref *root, XRef *xRef, const char *fileName, Goffset fileSize) { Dict *trailerDict = new Dict(xRef); @@ -1308,7 +1313,7 @@ Dict *PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Goffset startxR obj1.free(); GBool hasEncrypt = gFalse; - if (!xRef->getTrailerDict()->isNone()) { + if (!stripEncryption && !xRef->getTrailerDict()->isNone()) { Object obj2; xRef->getTrailerDict()->dictLookupNF("Encrypt", &obj2); if (!obj2.isNull()) { @@ -1401,7 +1406,7 @@ void PDFDoc::writeXRefStreamTrailer (Dict *trailerDict, XRef *uxref, Ref *uxrefS } void PDFDoc::writeXRefTableTrailer(Goffset uxrefOffset, XRef *uxref, GBool writeAllEntries, - int uxrefSize, OutStream* outStr, GBool incrUpdate) + int uxrefSize, OutStream* outStr, GBool incrUpdate, GBool stripEncryption) { const char *fileNameA = fileName ? fileName->getCString() : NULL; // file size (doesn't include the trailer) @@ -1415,7 +1420,7 @@ void PDFDoc::writeXRefTableTrailer(Goffset uxrefOffset, XRef *uxref, GBool write Ref ref; ref.num = getXRef()->getRootNum(); ref.gen = getXRef()->getRootGen(); - Dict * trailerDict = createTrailerDict(uxrefSize, incrUpdate, getStartXRef(), &ref, + Dict * trailerDict = createTrailerDict(uxrefSize, incrUpdate, stripEncryption, getStartXRef(), &ref, getXRef(), fileNameA, fileSize); writeXRefTableTrailer(trailerDict, uxref, writeAllEntries, uxrefOffset, outStr, getXRef()); delete trailerDict; diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h index 6c40f7b..7f55946 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -66,7 +66,8 @@ class StructTreeRoot; enum PDFWriteMode { writeStandard, writeForceRewrite, - writeForceIncremental + writeForceIncremental, + writeStripEncryption }; //------------------------------------------------------------------------ @@ -258,7 +259,7 @@ public: static void writeHeader(OutStream *outStr, int major, int minor); // Ownership goes to the caller - static Dict *createTrailerDict (int uxrefSize, GBool incrUpdate, Goffset startxRef, + static Dict *createTrailerDict (int uxrefSize, GBool incrUpdate, GBool stripEncryption, Goffset startxRef, Ref *root, XRef *xRef, const char *fileName, Goffset fileSize); static void writeXRefTableTrailer (Dict *trailerDict, XRef *uxref, GBool writeAllEntries, Goffset uxrefOffset, OutStream* outStr, XRef *xRef); @@ -285,11 +286,11 @@ private: static void writeStream (Stream* str, OutStream* outStr); static void writeRawStream (Stream* str, OutStream* outStr); void writeXRefTableTrailer (Goffset uxrefOffset, XRef *uxref, GBool writeAllEntries, - int uxrefSize, OutStream* outStr, GBool incrUpdate); + int uxrefSize, OutStream* outStr, GBool incrUpdate, GBool stripEncryption); static void writeString (GooString* s, OutStream* outStr, Guchar *fileKey, CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen); void saveIncrementalUpdate (OutStream* outStr); - void saveCompleteRewrite (OutStream* outStr); + void saveCompleteRewrite (OutStream* outStr, GBool stripEncryption); Page *parsePage(int page); diff --git a/utils/pdfunite.cc b/utils/pdfunite.cc index b35090c..764f68a 100644 --- a/utils/pdfunite.cc +++ b/utils/pdfunite.cc @@ -298,7 +298,7 @@ int main (int argc, char *argv[]) Ref ref; ref.num = rootNum; ref.gen = 0; - Dict *trailerDict = PDFDoc::createTrailerDict(objectsCount, gFalse, 0, &ref, yRef, + Dict *trailerDict = PDFDoc::createTrailerDict(objectsCount, gFalse, gFalse, 0, &ref, yRef, fileName, outStr->getPos()); PDFDoc::writeXRefTableTrailer(trailerDict, yRef, gFalse /* do not write unnecessary entries */, uxrefOffset, outStr, yRef); -- 2.4.6 From 13808633ea3b1860c23292457da061b48c3c6027 Mon Sep 17 00:00:00 2001 From: Adam Reichold <[email protected]> Date: Sat, 25 Jul 2015 14:08:16 +0200 Subject: [PATCH 2/2] [Qt] Add force-write and strip-encryption flags Extend the PDF converter options by two flags that force a rewrite and optionally strip the encryption from the document. --- qt4/src/poppler-pdf-converter.cc | 13 ++++++++++++- qt4/src/poppler-qt4.h | 4 +++- qt5/src/poppler-pdf-converter.cc | 13 ++++++++++++- qt5/src/poppler-qt5.h | 4 +++- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/qt4/src/poppler-pdf-converter.cc b/qt4/src/poppler-pdf-converter.cc index 9699b75..8350267 100644 --- a/qt4/src/poppler-pdf-converter.cc +++ b/qt4/src/poppler-pdf-converter.cc @@ -92,7 +92,18 @@ bool PDFConverter::convert() QIODeviceOutStream stream(dev); if (d->opts & WithChanges) { - errorCode = d->document->doc->saveAs(&stream); + PDFWriteMode mode = writeStandard; + + if (d->opts & StripEncryption) + { + mode = writeStripEncryption; + } + else if (d->opts & ForceRewrite) + { + mode = writeForceRewrite; + } + + errorCode = d->document->doc->saveAs(&stream, mode); } else { diff --git a/qt4/src/poppler-qt4.h b/qt4/src/poppler-qt4.h index c0340a4..fb65e11 100644 --- a/qt4/src/poppler-qt4.h +++ b/qt4/src/poppler-qt4.h @@ -1668,7 +1668,9 @@ height = dummy.height(); Options for the PDF export. */ enum PDFOption { - WithChanges = 0x00000001 ///< The changes done to the document are saved as well + WithChanges = 0x00000001, ///< The changes done to the document are saved as well + ForceRewrite = 0x00000002, ///< The document is rewritten instead of update incrementally (only applicable if WithChanges is also set) \since 0.35 + StripEncryption = 0x00000004 ///< The document is saved without encryption (only applicable if WithChanges is also set and implies ForceRewrite) \since 0.35 }; Q_DECLARE_FLAGS( PDFOptions, PDFOption ) diff --git a/qt5/src/poppler-pdf-converter.cc b/qt5/src/poppler-pdf-converter.cc index 557a9f8..c198c09 100644 --- a/qt5/src/poppler-pdf-converter.cc +++ b/qt5/src/poppler-pdf-converter.cc @@ -92,7 +92,18 @@ bool PDFConverter::convert() QIODeviceOutStream stream(dev); if (d->opts & WithChanges) { - errorCode = d->document->doc->saveAs(&stream); + PDFWriteMode mode = writeStandard; + + if (d->opts & StripEncryption) + { + mode = writeStripEncryption; + } + else if (d->opts & ForceRewrite) + { + mode = writeForceRewrite; + } + + errorCode = d->document->doc->saveAs(&stream, mode); } else { diff --git a/qt5/src/poppler-qt5.h b/qt5/src/poppler-qt5.h index b159477..80e87d7 100644 --- a/qt5/src/poppler-qt5.h +++ b/qt5/src/poppler-qt5.h @@ -1629,7 +1629,9 @@ height = dummy.height(); Options for the PDF export. */ enum PDFOption { - WithChanges = 0x00000001 ///< The changes done to the document are saved as well + WithChanges = 0x00000001, ///< The changes done to the document are saved as well + ForceRewrite = 0x00000002, ///< The document is rewritten instead of update incrementally (only applicable if WithChanges is also set) \since 0.35 + StripEncryption = 0x00000004 ///< The document is saved without encryption (only applicable if WithChanges is also set and implies ForceRewrite) \since 0.35 }; Q_DECLARE_FLAGS( PDFOptions, PDFOption ) -- 2.4.6
signature.asc
Description: OpenPGP digital signature
_______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
