Commit e3167c1a609a1f5262d8308dd94845d557e235d8
1 parent
9732de7e
Fix linearization for files with nonstandard ID length
Showing
7 changed files
with
72 additions
and
10 deletions
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->runtest("check output", |
| 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
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
qpdf/qtest/qpdf/short-id-linearized.pdf
0 → 100644
No preview for this file type