Commit e3167c1a609a1f5262d8308dd94845d557e235d8

Authored by Jay Berkenbilt
1 parent 9732de7e

Fix linearization for files with nonstandard ID length

include/qpdf/QPDFWriter.hh
... ... @@ -414,6 +414,7 @@ class QPDFWriter
414 414 void initializeSpecialStreams();
415 415 void preserveObjectStreams();
416 416 void generateObjectStreams();
  417 + std::string getOriginalID1();
417 418 void generateID();
418 419 void interpretR3EncryptionParameters(
419 420 std::set<int>& bits_to_clear,
... ...
libqpdf/QPDFWriter.cc
... ... @@ -1246,8 +1246,28 @@ QPDFWriter::writeTrailer(trailer_e which, int size, bool xref_stream,
1246 1246 writeString(" /ID [");
1247 1247 if (linearization_pass == 1)
1248 1248 {
1249   - writeString("<00000000000000000000000000000000>"
1250   - "<00000000000000000000000000000000>");
  1249 + std::string original_id1 = getOriginalID1();
  1250 + if (original_id1.empty())
  1251 + {
  1252 + writeString("<00000000000000000000000000000000>");
  1253 + }
  1254 + else
  1255 + {
  1256 + // Write a string of zeroes equal in length to the
  1257 + // representation of the original ID. While writing the
  1258 + // original ID would have the same number of bytes, it
  1259 + // would cause a change to the deterministic ID generated
  1260 + // by older versions of the software that hard-coded the
  1261 + // length of the ID to 16 bytes.
  1262 + writeString("<");
  1263 + size_t len = QPDF_String(original_id1).unparse(true).length() - 2;
  1264 + for (size_t i = 0; i < len; ++i)
  1265 + {
  1266 + writeString("0");
  1267 + }
  1268 + writeString(">");
  1269 + }
  1270 + writeString("<00000000000000000000000000000000>");
1251 1271 }
1252 1272 else
1253 1273 {
... ... @@ -1952,6 +1972,20 @@ QPDFWriter::writeObject(QPDFObjectHandle object, int object_stream_index)
1952 1972 }
1953 1973 }
1954 1974  
  1975 +std::string
  1976 +QPDFWriter::getOriginalID1()
  1977 +{
  1978 + QPDFObjectHandle trailer = this->m->pdf.getTrailer();
  1979 + if (trailer.hasKey("/ID"))
  1980 + {
  1981 + return trailer.getKey("/ID").getArrayItem(0).getStringValue();
  1982 + }
  1983 + else
  1984 + {
  1985 + return "";
  1986 + }
  1987 +}
  1988 +
1955 1989 void
1956 1990 QPDFWriter::generateID()
1957 1991 {
... ... @@ -2042,12 +2076,9 @@ QPDFWriter::generateID()
2042 2076 // generated ID for both.
2043 2077  
2044 2078 this->m->id2 = result;
2045   - if (trailer.hasKey("/ID"))
2046   - {
2047   - // Note: keep /ID from old file even if --static-id was given.
2048   - this->m->id1 = trailer.getKey("/ID").getArrayItem(0).getStringValue();
2049   - }
2050   - else
  2079 + // Note: keep /ID from old file even if --static-id was given.
  2080 + this->m->id1 = getOriginalID1();
  2081 + if (this->m->id1.empty())
2051 2082 {
2052 2083 this->m->id1 = this->m->id2;
2053 2084 }
... ...
qpdf/qtest/qpdf.test
... ... @@ -240,7 +240,7 @@ foreach my $d (@bug_tests)
240 240 show_ntests();
241 241 # ----------
242 242 $td->notify("--- Miscellaneous Tests ---");
243   -$n_tests += 87;
  243 +$n_tests += 93;
244 244  
245 245 $td->runtest("qpdf version",
246 246 {$td->COMMAND => "qpdf --version"},
... ... @@ -303,7 +303,8 @@ $td-&gt;runtest(&quot;check output&quot;,
303 303 {$td->FILE => "unreferenced-indirect-scalar.out"});
304 304  
305 305 # Encrypt files whose /ID strings are other than 32 bytes long (bug
306   -# 2991412).
  306 +# 2991412). Also linearize these files, which was reported in a
  307 +# separate bug by email.
307 308 foreach my $file (qw(short-id long-id))
308 309 {
309 310 $td->runtest("encrypt $file.pdf",
... ... @@ -318,6 +319,23 @@ foreach my $file (qw(short-id long-id))
318 319 {$td->FILE => "$file-check.out",
319 320 $td->EXIT_STATUS => 0},
320 321 $td->NORMALIZE_NEWLINES);
  322 +
  323 + $td->runtest("linearize $file.pdf",
  324 + {$td->COMMAND =>
  325 + "qpdf --deterministic-id --linearize $file.pdf a.pdf"},
  326 + {$td->STRING => "",
  327 + $td->EXIT_STATUS => 0},
  328 + $td->NORMALIZE_NEWLINES);
  329 +
  330 + $td->runtest("check output",
  331 + {$td->FILE => "a.pdf"},
  332 + {$td->FILE => "$file-linearized.pdf"});
  333 +
  334 + $td->runtest("check $file.pdf",
  335 + {$td->COMMAND => "qpdf --check a.pdf"},
  336 + {$td->FILE => "$file-linearized-check.out",
  337 + $td->EXIT_STATUS => 0},
  338 + $td->NORMALIZE_NEWLINES);
321 339 }
322 340  
323 341 # Handle file with invalid xref table and object 0 as a regular object
... ...
qpdf/qtest/qpdf/long-id-linearized-check.out 0 → 100644
  1 +checking a.pdf
  2 +PDF Version: 1.3
  3 +File is not encrypted
  4 +File is linearized
  5 +No syntax or stream encoding errors found; the file may still contain
  6 +errors that qpdf cannot detect
... ...
qpdf/qtest/qpdf/long-id-linearized.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/short-id-linearized-check.out 0 → 100644
  1 +checking a.pdf
  2 +PDF Version: 1.3
  3 +File is not encrypted
  4 +File is linearized
  5 +No syntax or stream encoding errors found; the file may still contain
  6 +errors that qpdf cannot detect
... ...
qpdf/qtest/qpdf/short-id-linearized.pdf 0 → 100644
No preview for this file type