diff --git a/ChangeLog b/ChangeLog index 1265467c..7f4d64f7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2013-02-23 Jay Berkenbilt + + * Bug fix: properly handle overridden compressed objects. When + caching objects from an object stream, only cache objects that, + based on the xref table, would actually be resolved into this + stream. Prior to this fix, if an object stream A contained an + object B that was overridden by an appended section of the file, + qpdf would cache the old value of B if any non-overridden member + of A was accessed before B. This commit fixes that bug. + 2013-01-31 Jay Berkenbilt * Do not remove libtool's .la file during the make install step. diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 5ee043b9..5860fb11 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -1538,20 +1538,31 @@ QPDF::resolveObjectsInStream(int obj_stream_number) offsets[num] = offset + first; } + // To avoid having to read the object stream multiple times, store + // all objects that would be found here in the cache. Remember + // that some objects stored here might have been overridden by new + // objects appended to the file, so it is necessary to recheck the + // xref table and only cache what would actually be resolved here. for (std::map::iterator iter = offsets.begin(); iter != offsets.end(); ++iter) { int obj = (*iter).first; - int offset = (*iter).second; - input->seek(offset, SEEK_SET); - QPDFObjectHandle oh = readObject(input, "", obj, 0, true); - - // Store in cache ObjGen og(obj, 0); - - this->obj_cache[og] = - ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), - end_before_space, end_after_space); + QPDFXRefEntry const& entry = this->xref_table[og]; + if ((entry.getType() == 2) && + (entry.getObjStreamNumber() == obj_stream_number)) + { + int offset = (*iter).second; + input->seek(offset, SEEK_SET); + QPDFObjectHandle oh = readObject(input, "", obj, 0, true); + this->obj_cache[og] = + ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), + end_before_space, end_after_space); + } + else + { + QTC::TC("qpdf", "QPDF not caching overridden objstm object"); + } } } diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index b09e966c..31e15495 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -261,3 +261,4 @@ qpdf-c called qpdf_set_r5_encryption_parameters 0 qpdf-c called qpdf_set_r6_encryption_parameters 0 QPDFObjectHandle EOF in inline image 0 QPDFObjectHandle inline image token 0 +QPDF not caching overridden objstm object 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index f447bd83..8375e5f2 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -199,7 +199,7 @@ $td->runtest("remove page we don't have", show_ntests(); # ---------- $td->notify("--- Miscellaneous Tests ---"); -$n_tests += 60; +$n_tests += 61; $td->runtest("qpdf version", {$td->COMMAND => "qpdf --version"}, @@ -484,6 +484,18 @@ $td->runtest("content stream errors", $td->EXIT_STATUS => 2}, $td->NORMALIZE_NEWLINES); +# The file override-compressed-object.pdf contains an object stream +# with four strings in it. The file is then appended. The appended +# section overrides one of the four strings with a string in another +# object stream and another one in an uncompressed object. The other +# two strings are left alone. The test case exercises that all four +# objects have the correct value. +$td->runtest("overridden compressed objects", + {$td->COMMAND => "test_driver 38 override-compressed-object.pdf"}, + {$td->FILE => "override-compressed-object.out", + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + show_ntests(); # ---------- $td->notify("--- Numeric range parsing tests ---"); diff --git a/qpdf/qtest/qpdf/override-compressed-object.out b/qpdf/qtest/qpdf/override-compressed-object.out new file mode 100644 index 00000000..a3fbd51d --- /dev/null +++ b/qpdf/qtest/qpdf/override-compressed-object.out @@ -0,0 +1,5 @@ +(orig-1) +(override-2) +(override-3) +(orig-4) +test 38 done diff --git a/qpdf/qtest/qpdf/override-compressed-object.pdf b/qpdf/qtest/qpdf/override-compressed-object.pdf new file mode 100644 index 00000000..0647b7fe Binary files /dev/null and b/qpdf/qtest/qpdf/override-compressed-object.pdf differ diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index 799ea4ba..d6534abf 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -1302,6 +1302,15 @@ void runtest(int n, char const* filename1, char const* arg2) QPDFObjectHandle::parseContentStream(contents, &cb); } } + else if (n == 38) + { + // Designed for override-compressed-object.pdf + QPDFObjectHandle qtest = pdf.getRoot().getKey("/QTest"); + for (int i = 0; i < qtest.getArrayNItems(); ++i) + { + std::cout << qtest.getArrayItem(i).unparseResolved() << std::endl; + } + } else { throw std::runtime_error(std::string("invalid test ") +