summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2013-02-23 23:41:27 +0100
committerJay Berkenbilt <ejb@ql.org>2013-02-23 23:51:17 +0100
commit6c7bf114dc0402dfbfaef4586f05dfd398e57e16 (patch)
treeb7cc8bf0e477e3e4fe28f3a20f2f656788e667d8
parent7e7c93951f7d0af4cd249f9bbbcf3d79ac500a7c (diff)
downloadqpdf-6c7bf114dc0402dfbfaef4586f05dfd398e57e16.tar.zst
Bug fix: properly handle overridden compressed objects
When caching objects in an object stream, only cache objects that still resolve to that stream. See Changelog mod from this commit for details.
-rw-r--r--ChangeLog10
-rw-r--r--libqpdf/QPDF.cc29
-rw-r--r--qpdf/qpdf.testcov1
-rw-r--r--qpdf/qtest/qpdf.test14
-rw-r--r--qpdf/qtest/qpdf/override-compressed-object.out5
-rw-r--r--qpdf/qtest/qpdf/override-compressed-object.pdfbin0 -> 1817 bytes
-rw-r--r--qpdf/test_driver.cc9
7 files changed, 58 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 1265467c..7f4d64f7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2013-02-23 Jay Berkenbilt <ejb@ql.org>
+
+ * 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 <ejb@ql.org>
* 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<int, int>::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
--- /dev/null
+++ b/qpdf/qtest/qpdf/override-compressed-object.pdf
Binary files 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 ") +