diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index 631f9a70..19d16459 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -983,41 +983,41 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) { XRef *uxref; int c; //copy the original file BaseStream *copyStr = str->copy(); copyStr->reset(); while ((c = copyStr->getChar()) != EOF) { outStr->put(c); } copyStr->close(); delete copyStr; Guchar *fileKey; CryptAlgorithm encAlgorithm; int keyLength; xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); uxref = new XRef(); uxref->add(0, 65535, 0, gFalse); xref->lock(); - for(int i=0; igetNumObjects(); i++) { + for (int i : xref->getObjectIds()) { if ((xref->getEntry(i)->type == xrefEntryFree) && (xref->getEntry(i)->gen == 0)) //we skip the irrelevant free objects continue; if (xref->getEntry(i)->getFlag(XRefEntry::Updated)) { //we have an updated object Ref ref; ref.num = i; ref.gen = xref->getEntry(i)->type == xrefEntryCompressed ? 0 : xref->getEntry(i)->gen; if (xref->getEntry(i)->type != xrefEntryFree) { Object obj1 = xref->fetch(ref.num, ref.gen, 1); Goffset offset = writeObjectHeader(&ref, outStr); writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); writeObjectFooter(outStr); uxref->add(ref.num, ref.gen, offset, gTrue); } else { uxref->add(ref.num, ref.gen, 0, gFalse); } } } xref->unlock(); @@ -1053,41 +1053,41 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) } delete uxref; } void PDFDoc::saveCompleteRewrite (OutStream* outStr) { // 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); outStr->printf("%%PDF-%d.%d\r\n",pdfMajorVersion,pdfMinorVersion); XRef *uxref = new XRef(); uxref->add(0, 65535, 0, gFalse); xref->lock(); - for(int i=0; igetNumObjects(); i++) { + for(int i: xref->getObjectIds()) { Ref ref; XRefEntryType type = xref->getEntry(i)->type; if (type == xrefEntryFree) { ref.num = i; ref.gen = xref->getEntry(i)->gen; /* the XRef class adds a lot of irrelevant free entries, we only want the significant one and we don't want the one with num=0 because it has already been added (gen = 65535)*/ if (ref.gen > 0 && ref.num > 0) uxref->add(ref.num, ref.gen, 0, gFalse); } else if (xref->getEntry(i)->getFlag(XRefEntry::DontRewrite)) { // This entry must not be written, put a free entry instead (with incremented gen) ref.num = i; ref.gen = xref->getEntry(i)->gen + 1; uxref->add(ref.num, ref.gen, 0, gFalse); } else if (type == xrefEntryUncompressed){ ref.num = i; ref.gen = xref->getEntry(i)->gen; Object obj1 = xref->fetch(ref.num, ref.gen, 1); Goffset offset = writeObjectHeader(&ref, outStr); // Write unencrypted objects in unencrypted form diff --git a/poppler/XRef.cc b/poppler/XRef.cc index 95e1a1d4..1085902f 100644 --- a/poppler/XRef.cc +++ b/poppler/XRef.cc @@ -1629,40 +1629,50 @@ XRefEntry *XRef::getEntry(int i, GBool complainIfMissing) static XRefEntry dummy; dummy.offset = 0; dummy.gen = -1; dummy.type = xrefEntryNone; dummy.flags = 0; return &dummy; } if (entries[i].type == xrefEntryNone) { if (complainIfMissing) { error(errSyntaxError, -1, "Invalid XRef entry"); } entries[i].type = xrefEntryFree; } } } return &entries[i]; } +std::vector XRef::getObjectIds() const { + std::vector objectIds; + for (int i=0; igetType()) { case objArray: { Array *array = obj->getArray(); for (int i = 0; i < array->getLength(); i++) { obj1 = array->getNF(i); markUnencrypted(&obj1); } break; } case objStream: case objDict: { Dict *dict; if (obj->getType() == objStream) { Stream *stream = obj->getStream(); diff --git a/poppler/XRef.h b/poppler/XRef.h index 686b3eb7..58738e17 100644 --- a/poppler/XRef.h +++ b/poppler/XRef.h @@ -169,40 +169,44 @@ public: // Get end position for a stream in a damaged file. // Returns false if unknown or file is not damaged. GBool getStreamEnd(Goffset streamStart, Goffset *streamEnd); // Retuns the entry that belongs to the offset int getNumEntry(Goffset offset); // Scans the document and sets special flags in all xref entries. One of those // flags is Unencrypted, which affects how the object is fetched. Therefore, // this function must be called before fetching unencrypted objects (e.g. // Encrypt dictionary, XRef streams). Note that the code that initializes // decryption doesn't need to call this function, because it runs before // decryption is enabled, and therefore the Unencrypted flag is ignored. void scanSpecialFlags(); // Direct access. XRefEntry *getEntry(int i, GBool complainIfMissing = gTrue); Object *getTrailerDict() { return &trailerDict; } + // Get object IDs of all free, uncompressed and compressed objects mentioned by XRef + // Gaps of xrefEntryNone entries are excluded. + std::vector getObjectIds() const; + // 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); void removeIndirectObject(Ref r); void add(int num, int gen, Goffset offs, GBool used); // Output XRef table to stream void writeTableToFile(OutStream* outStr, GBool writeAllEntries); // Output XRef stream contents to GooString and fill trailerDict fields accordingly void writeStreamToBuffer(GooString *stmBuf, Dict *xrefDict, XRef *xref); // to be thread safe during write where changes are not allowed void lock(); void unlock();