Commit 4499e04b5714747eb954420f8133e650a5137d45
1 parent
35d72c82
better recovery for appended files with damaged cross-reference tables
git-svn-id: svn+q:///qpdf/trunk@649 71b93d88-0707-0410-a8cf-f5a4172ac649
Showing
4 changed files
with
37 additions
and
6 deletions
ChangeLog
| 1 | +2009-02-20 Jay Berkenbilt <ejb@ql.org> | ||
| 2 | + | ||
| 3 | + * libqpdf/QPDF.cc (QPDF::insertXrefEntry): when recovering the | ||
| 4 | + cross-reference table, have objects we encounter later in the file | ||
| 5 | + supersede those we found earlier. This improves the chances of | ||
| 6 | + being able to recover appended files with damaged cross-reference | ||
| 7 | + tables. | ||
| 8 | + | ||
| 1 | 2009-02-19 Jay Berkenbilt <ejb@ql.org> | 9 | 2009-02-19 Jay Berkenbilt <ejb@ql.org> |
| 2 | 10 | ||
| 3 | * libqpdf/Pl_LZWDecoder.cc: correct logic error for previously | 11 | * libqpdf/Pl_LZWDecoder.cc: correct logic error for previously |
TODO
include/qpdf/QPDF.hh
| @@ -333,7 +333,8 @@ class QPDF | @@ -333,7 +333,8 @@ class QPDF | ||
| 333 | int read_xrefTable(off_t offset); | 333 | int read_xrefTable(off_t offset); |
| 334 | int read_xrefStream(off_t offset); | 334 | int read_xrefStream(off_t offset); |
| 335 | int processXRefStream(off_t offset, QPDFObjectHandle& xref_stream); | 335 | int processXRefStream(off_t offset, QPDFObjectHandle& xref_stream); |
| 336 | - void insertXrefEntry(int obj, int f0, int f1, int f2); | 336 | + void insertXrefEntry(int obj, int f0, int f1, int f2, |
| 337 | + bool overwrite = false); | ||
| 337 | QPDFObjectHandle readObject( | 338 | QPDFObjectHandle readObject( |
| 338 | InputSource*, int objid, int generation, | 339 | InputSource*, int objid, int generation, |
| 339 | bool in_object_stream); | 340 | bool in_object_stream); |
libqpdf/QPDF.cc
| @@ -435,7 +435,7 @@ QPDF::reconstruct_xref(QPDFExc& e) | @@ -435,7 +435,7 @@ QPDF::reconstruct_xref(QPDFExc& e) | ||
| 435 | int obj = atoi(m.getMatch(1).c_str()); | 435 | int obj = atoi(m.getMatch(1).c_str()); |
| 436 | int gen = atoi(m.getMatch(2).c_str()); | 436 | int gen = atoi(m.getMatch(2).c_str()); |
| 437 | int offset = this->file.getLastOffset(); | 437 | int offset = this->file.getLastOffset(); |
| 438 | - insertXrefEntry(obj, 1, offset, gen); | 438 | + insertXrefEntry(obj, 1, offset, gen, true); |
| 439 | } | 439 | } |
| 440 | else if ((! this->trailer.isInitialized()) && | 440 | else if ((! this->trailer.isInitialized()) && |
| 441 | trailer_re.match(line.c_str())) | 441 | trailer_re.match(line.c_str())) |
| @@ -865,11 +865,15 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj) | @@ -865,11 +865,15 @@ QPDF::processXRefStream(off_t xref_offset, QPDFObjectHandle& xref_obj) | ||
| 865 | } | 865 | } |
| 866 | 866 | ||
| 867 | void | 867 | void |
| 868 | -QPDF::insertXrefEntry(int obj, int f0, int f1, int f2) | 868 | +QPDF::insertXrefEntry(int obj, int f0, int f1, int f2, bool overwrite) |
| 869 | { | 869 | { |
| 870 | // Populate the xref table in such a way that the first reference | 870 | // Populate the xref table in such a way that the first reference |
| 871 | // to an object that we see, which is the one in the latest xref | 871 | // to an object that we see, which is the one in the latest xref |
| 872 | - // table in which it appears, is the one that gets stored. | 872 | + // table in which it appears, is the one that gets stored. This |
| 873 | + // works because we are reading more recent appends before older | ||
| 874 | + // ones. Exception: if overwrite is true, then replace any | ||
| 875 | + // existing object. This is used in xref recovery mode, which | ||
| 876 | + // reads the file from beginning to end. | ||
| 873 | 877 | ||
| 874 | // If there is already an entry for this object and generation in | 878 | // If there is already an entry for this object and generation in |
| 875 | // the table, it means that a later xref table has registered this | 879 | // the table, it means that a later xref table has registered this |
| @@ -879,8 +883,16 @@ QPDF::insertXrefEntry(int obj, int f0, int f1, int f2) | @@ -879,8 +883,16 @@ QPDF::insertXrefEntry(int obj, int f0, int f1, int f2) | ||
| 879 | ObjGen og(obj, gen); | 883 | ObjGen og(obj, gen); |
| 880 | if (this->xref_table.count(og)) | 884 | if (this->xref_table.count(og)) |
| 881 | { | 885 | { |
| 882 | - QTC::TC("qpdf", "QPDF xref reused object"); | ||
| 883 | - return; | 886 | + if (overwrite) |
| 887 | + { | ||
| 888 | + QTC::TC("qpdf", "QPDF xref overwrite object"); | ||
| 889 | + this->xref_table.erase(og); | ||
| 890 | + } | ||
| 891 | + else | ||
| 892 | + { | ||
| 893 | + QTC::TC("qpdf", "QPDF xref reused object"); | ||
| 894 | + return; | ||
| 895 | + } | ||
| 884 | } | 896 | } |
| 885 | if (this->deleted_objects.count(obj)) | 897 | if (this->deleted_objects.count(obj)) |
| 886 | { | 898 | { |