diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index dd93a64..f52d498 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -610,6 +610,15 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) OutStream *outStr; XRef *yRef, *countRef; int rootNum = getXRef()->getNumObjects() + 1; + + // 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); if (pageNo < 1 || pageNo > getNumPages()) { error(errInternal, -1, "Illegal pageNo: {0:d}({1:d})", pageNo, getNumPages() ); @@ -634,7 +643,18 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) outStr = new FileOutStream(f,0); yRef = new XRef(getXRef()->getTrailerDict()); + Object encrypt; + getXRef()->getTrailerDict()->dictLookup("Encrypt", &encrypt); + + if (secHdlr != NULL && !secHdlr->isUnencrypted()) { + yRef->setEncryption(secHdlr->getPermissionFlags(), + secHdlr->getOwnerPasswordOk(), fileKey, keyLength, secHdlr->getEncVersion(), secHdlr->getEncRevision(), encAlgorithm); + } countRef = new XRef(); + Object *trailerObj = getXRef()->getTrailerDict(); + if (trailerObj->isDict()) { + markPageObjects(trailerObj->getDict(), yRef, countRef, 0); + } yRef->add(0, 65535, 0, gFalse); writeHeader(outStr, getPDFMajorVersion(), getPDFMinorVersion()); @@ -644,7 +664,6 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) if (infoObj.isDict()) { Dict *infoDict = infoObj.getDict(); markPageObjects(infoDict, yRef, countRef, 0); - Object *trailerObj = getXRef()->getTrailerDict(); if (trailerObj->isDict()) { Dict *trailerDict = trailerObj->getDict(); Object ref; @@ -673,6 +692,7 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) Dict *pageDict = page.getDict(); markPageObjects(pageDict, yRef, countRef, 0); + yRef->markUnencrypted(); Guint objectsCount = writePageObjects(outStr, yRef, 0); yRef->add(rootNum,0,outStr->getPos(),gTrue); @@ -1498,7 +1518,8 @@ void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint n const char *key = pageDict->getKey(n); Object value; pageDict->getValNF(n, &value); if (strcmp(key, "Parent") != 0 && - strcmp(key, "Pages") != 0) { + strcmp(key, "Pages") != 0 && + strcmp(key, "Root") != 0) { markObject(&value, xRef, countRef, numOffset); } value.free(); @@ -1508,6 +1529,10 @@ void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint n Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset) { Guint objectsCount = 0; //count the number of objects in the XRef(s) + Guchar *fileKey; + CryptAlgorithm encAlgorithm; + int keyLength; + xRef->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); for (int n = numOffset; n < xRef->getNumObjects(); n++) { if (xRef->getEntry(n)->type != xrefEntryFree) { @@ -1518,7 +1543,11 @@ Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset) objectsCount++; getXRef()->fetch(ref.num - numOffset, ref.gen, &obj); Guint offset = writeObjectHeader(&ref, outStr); - writeObject(&obj, outStr, xRef, numOffset, NULL, cryptRC4, 0, 0, 0); + if (xRef->getEntry(n)->getFlag(XRefEntry::Unencrypted)) { + writeObject(&obj, outStr, NULL, cryptRC4, 0, 0, 0); + } else { + writeObject(&obj, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); + } writeObjectFooter(outStr); xRef->add(ref.num, ref.gen, offset, gTrue); obj.free(); diff --git a/poppler/XRef.cc b/poppler/XRef.cc index 7ca205e..acbc16a 100644 --- a/poppler/XRef.cc +++ b/poppler/XRef.cc @@ -276,6 +276,11 @@ XRef::XRef() { XRef::XRef(Object *trailerDictA) { init(); + + encrypted = gFalse; + permFlags = defPermFlags; + ownerPasswordOk = gFalse; + if (trailerDictA->isDict()) trailerDict.initDict(trailerDictA->getDict()); } @@ -1582,4 +1587,14 @@ void XRef::scanSpecialFlags() { obj.free(); } +void XRef::markUnencrypted() { + // Mark objects referred from the Encrypt dict as Unencrypted + Object obj; + trailerDict.dictLookupNF("Encrypt", &obj); + if (obj.isRef()) { + XRefEntry *e = getEntry(obj.getRefNum()); + e->setFlag(XRefEntry::Unencrypted, gTrue); + } + obj.free(); +} diff --git a/poppler/XRef.h b/poppler/XRef.h index 310572f..2defc6c 100644 --- a/poppler/XRef.h +++ b/poppler/XRef.h @@ -113,6 +113,8 @@ public: Guchar *fileKeyA, int keyLengthA, int encVersionA, int encRevisionA, CryptAlgorithm encAlgorithmA); + // Mark Encrypt entry as Unencrypted + void markUnencrypted(); void getEncryptionParameters(Guchar **fileKeyA, CryptAlgorithm *encAlgorithmA, int *keyLengthA); diff --git a/utils/pdfseparate.cc b/utils/pdfseparate.cc index 25fac5a..35ae020 100644 --- a/utils/pdfseparate.cc +++ b/utils/pdfseparate.cc @@ -52,10 +52,6 @@ bool extractPages (const char *srcFileName, const char *destFileName) { error(errSyntaxError, -1, "Could not extract page(s) from damaged file ('{0:s}')", srcFileName); return false; } - if (doc->isEncrypted()) { - error(errSyntaxError, -1, "Could not extract page(s) from encrypted file ('{0:s}')", srcFileName); - return false; - } if (firstPage == 0 && lastPage == 0) { firstPage = 1;