From 57c01ef81ff11b208188bbdedc98b6ce20c786b3 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sun, 26 Jan 2020 16:43:55 -0500 Subject: [PATCH] In qdf mode, don't write extra XRef streams (fixes #386) fix-qdf assumes there is exactly one XRef stream and that it is at the end of the file. --- ChangeLog | 7 +++++++ libqpdf/QPDFWriter.cc | 15 +++++++++++++++ qpdf/qpdf.testcov | 1 + qpdf/qtest/qpdf.test | 12 +++++++++++- qpdf/qtest/qpdf/compress-objstm-xref-qdf.pdf | Bin 0 -> 1249 bytes 5 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 qpdf/qtest/qpdf/compress-objstm-xref-qdf.pdf diff --git a/ChangeLog b/ChangeLog index 38749752..b65581ba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2020-01-26 Jay Berkenbilt + * Bug fix: in qdf mode, do not write out any XRef streams that may + have appeared in the original file. These are usually + unreferenced, but with --preserve-unreferenced, they could be + written out, which breaks fix-qdf's assumption that there is at + most one XRef stream and that it appears at the end of the file. + Fixes #386. + * Bug fix: when externalizing inline images, a colorspace value that was a lookup key in the page's /Resource -> /ColorSpace dictionary was not properly handled. Fixes #392. diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index 7b769ae4..5f97117d 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -1241,6 +1241,21 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object) " another file."); } + if (this->m->qdf_mode && + object.isStream() && object.getDict().getKey("/Type").isName() && + (object.getDict().getKey("/Type").getName() == "/XRef")) + { + // As a special case, do not output any extraneous XRef + // streams in QDF mode. Doing so will confuse fix-qdf, + // which expects to see only one XRef stream at the end of + // the file. This case can occur when creating a QDF from + // a file with object streams when preserving unreferenced + // objects since the old cross reference streams are not + // actually referenced by object number. + QTC::TC("qpdf", "QPDFWriter ignore XRef in qdf mode"); + return; + } + QPDFObjGen og = object.getObjGen(); if (this->m->obj_renumber.count(og) == 0) diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index db3de950..f16f0364 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -448,3 +448,4 @@ QPDFWriter stream in ostream 0 QPDFObjectHandle duplicate dict key 0 QPDFWriter no encryption sig contents 0 QPDFPageObjectHelper colorspace lookup 0 +QPDFWriter ignore XRef in qdf mode 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index f9bab01f..e42e204a 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -2779,7 +2779,7 @@ for (my $n = 16; $n <= 19; ++$n) show_ntests(); # ---------- $td->notify("--- Specific File Tests ---"); -$n_tests += 4; +$n_tests += 7; # Special PDF files that caused problems at some point @@ -2800,6 +2800,16 @@ $td->runtest("compress objstm and xref", $td->runtest("check output", {$td->FILE => "a.pdf"}, {$td->FILE => "compress-objstm-xref.pdf"}); +$td->runtest("qdf + preserved-unreferenced + xref streams", + {$td->COMMAND => "qpdf --qdf --preserve-unreferenced" . + " --static-id compress-objstm-xref.pdf a.pdf"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}); +$td->runtest("check output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "compress-objstm-xref-qdf.pdf"}); +$td->runtest("check fix-qdf idempotency", + {$td->COMMAND => "fix-qdf a.pdf"}, + {$td->FILE => "a.pdf", $td->EXIT_STATUS => 0}); show_ntests(); # ---------- diff --git a/qpdf/qtest/qpdf/compress-objstm-xref-qdf.pdf b/qpdf/qtest/qpdf/compress-objstm-xref-qdf.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d6b78a053f8f0a5b242fd053816b9373e6ff3da1 GIT binary patch literal 1249 zcmah|&2G~`5KdZ7`v%5Ho9=2+1u`#@^Xo&-cyDH@(?-`qF#lv)=b#-+r^+N9($bdEkP+-mt-d0XXrO zI|a_g^=4si$$zi%wfPJo7v!CTPp@fKlm_|%8xC1%3YFY44lWZAg-inXIP*dJAq&74 z2-pLRr&b24yC(!kE`I@8o~k{#uR#~tI?I!7b9Od90bX;OC2LiJK%Vmh#Zh9CtzHv_ z2LVI_;I#vY8epV%xdD%Yzsu4Rmbe0tHQ?0&)G~P#QZ|sh9a0io3WIP}#YZ|fDmNvB zO@bd(nkA=tU-NJ+o9Y>0ZHZeL(c3bcB?W$dD9>D#dRMHlVm3at3lSQJTn~a83INMT z@tj$qR|{ppuTSiLtp=j|XwrU@v}jM-XH-!K6-cjG?G3wnxNAWZO}0l1>cX8SrLw6x zZ`Jl*nQWC%_({IfX_l|SxyM4C%wYnarzO6AL)ZtHKqK0kZ65<eF0N=w_fL>B+f-B_J%CmC{^moJz|M4;R^2 zRH?mpHiqRuc+&GD9^g#(qc9R&^ku*UDMVlJF!G20zi~x%t+VdnuiJUrIl?De7wrh` g80|^-_#Rh3(0+DWQZ7wWn0d9F(nHMy9wKTU8&-T(jq literal 0 HcmV?d00001