Commit 173b944ef8f1dd3f971a6089a52fcd1ae07ca8f1
1 parent
4b642caf
Split qpdf.test into multiple test suites
This makes it a lot easier to run parts of the test suite.
Showing
103 changed files
with
7343 additions
and
5876 deletions
TODO
| ... | ... | @@ -39,13 +39,12 @@ Other (do in any order): |
| 39 | 39 | settings for QPDF and QPDFJob. This probably includes adding a |
| 40 | 40 | Pl_Ostream pipeline. |
| 41 | 41 | * Nice to have: |
| 42 | - * Split qpdf.test into multiple tests | |
| 43 | 42 | * In libtests, separate executables that need the object library |
| 44 | 43 | from those that strictly use public API. Move as many of the test |
| 45 | 44 | drivers from the qpdf directory into the latter category as long |
| 46 | 45 | as doing so isn't too troublesome from a coverage standpoint. |
| 47 | 46 | * Rework tests so that nothing is written into the source directory. |
| 48 | - * Ideally then the entire build could be done with a read-only | |
| 47 | + Ideally then the entire build could be done with a read-only | |
| 49 | 48 | source tree. |
| 50 | 49 | |
| 51 | 50 | Soon: Break ground on "Document-level work" | ... | ... |
qpdf/qtest/appearance_streams.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('appearance_streams'); | |
| 16 | + | |
| 17 | +my $n_tests = 12; | |
| 18 | + | |
| 19 | +foreach my $f ('need-appearances', | |
| 20 | + 'need-appearances-more', | |
| 21 | + 'need-appearances-more2', | |
| 22 | + 'need-appearances-more3') | |
| 23 | +{ | |
| 24 | + $td->runtest("generate appearances and flatten ($f)", | |
| 25 | + {$td->COMMAND => | |
| 26 | + "qpdf --qdf --no-original-object-ids --static-id" . | |
| 27 | + " --generate-appearances --flatten-annotations=all" . | |
| 28 | + " $f.pdf a.pdf"}, | |
| 29 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 30 | + $td->NORMALIZE_NEWLINES); | |
| 31 | + my $exp = 'appearances-a'; | |
| 32 | + if ($f =~ m/appearances(-.*)$/) | |
| 33 | + { | |
| 34 | + $exp .= $1; | |
| 35 | + } | |
| 36 | + $exp .= '.pdf'; | |
| 37 | + $td->runtest("compare files", | |
| 38 | + {$td->FILE => "a.pdf"}, | |
| 39 | + {$td->FILE => $exp}); | |
| 40 | +} | |
| 41 | + | |
| 42 | +$td->runtest("more choices", | |
| 43 | + {$td->COMMAND => | |
| 44 | + "qpdf --qdf --no-original-object-ids --static-id" . | |
| 45 | + " --generate-appearances" . | |
| 46 | + " more-choices.pdf b.pdf"}, | |
| 47 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 48 | + $td->NORMALIZE_NEWLINES); | |
| 49 | +# b.pdf still has forms | |
| 50 | +$td->runtest("compare files", | |
| 51 | + {$td->FILE => "b.pdf"}, | |
| 52 | + {$td->FILE => "appearances-b.pdf"}); | |
| 53 | + | |
| 54 | +my @choice_values = qw(1 2 11 12 quack); | |
| 55 | +$n_tests += 3 * scalar(@choice_values); | |
| 56 | +foreach my $i (@choice_values) | |
| 57 | +{ | |
| 58 | + # b.pdf was generated by qpdf and needs appearances | |
| 59 | + # test_driver 52 writes a.pdf | |
| 60 | + $td->runtest("set value to $i", | |
| 61 | + {$td->COMMAND => "test_driver 52 b.pdf $i"}, | |
| 62 | + {$td->STRING => "setting list1 value\ntest 52 done\n", | |
| 63 | + $td->EXIT_STATUS => 0}, | |
| 64 | + $td->NORMALIZE_NEWLINES); | |
| 65 | + $td->runtest("regenerate appearances", | |
| 66 | + {$td->COMMAND => | |
| 67 | + "qpdf --qdf --no-original-object-ids --static-id" . | |
| 68 | + " --generate-appearances" . | |
| 69 | + " a.pdf b.pdf"}, | |
| 70 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 71 | + $td->NORMALIZE_NEWLINES); | |
| 72 | + $td->runtest("compare files", | |
| 73 | + {$td->FILE => "b.pdf"}, | |
| 74 | + {$td->FILE => "appearances-$i.pdf"}); | |
| 75 | +} | |
| 76 | + | |
| 77 | +$td->runtest("Update resources from /DR", | |
| 78 | + {$td->COMMAND => | |
| 79 | + "qpdf --qdf --no-original-object-ids --static-id" . | |
| 80 | + " --generate-appearances" . | |
| 81 | + " resource-from-dr.pdf a.pdf"}, | |
| 82 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 83 | + $td->NORMALIZE_NEWLINES); | |
| 84 | +$td->runtest("compare files", | |
| 85 | + {$td->FILE => "a.pdf"}, | |
| 86 | + {$td->FILE => "resource-from-dr-out.pdf"}); | |
| 87 | + | |
| 88 | +cleanup(); | |
| 89 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/arg_parsing.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | +use File::Copy; | |
| 6 | + | |
| 7 | +unshift(@INC, '.'); | |
| 8 | +require qpdf_test_helpers; | |
| 9 | + | |
| 10 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 11 | + | |
| 12 | +require TestDriver; | |
| 13 | + | |
| 14 | +cleanup(); | |
| 15 | + | |
| 16 | +my $td = new TestDriver('arg_parsing'); | |
| 17 | + | |
| 18 | +my $n_tests = 13; | |
| 19 | + | |
| 20 | +$td->runtest("required argument", | |
| 21 | + {$td->COMMAND => "qpdf --password minimal.pdf"}, | |
| 22 | + {$td->REGEXP => "must be given as --password=pass", | |
| 23 | + $td->EXIT_STATUS => 2}, | |
| 24 | + $td->NORMALIZE_NEWLINES); | |
| 25 | +$td->runtest("required argument with choices", | |
| 26 | + {$td->COMMAND => "qpdf --decode-level minimal.pdf"}, | |
| 27 | + {$td->REGEXP => "must be given as --decode-level=\\{.*all.*\\}", | |
| 28 | + $td->EXIT_STATUS => 2}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | +$td->runtest("required argument with choices", | |
| 31 | + {$td->COMMAND => "qpdf --decode-level minimal.pdf"}, | |
| 32 | + {$td->REGEXP => "must be given as --decode-level=\\{.*all.*\\}", | |
| 33 | + $td->EXIT_STATUS => 2}, | |
| 34 | + $td->NORMALIZE_NEWLINES); | |
| 35 | +copy("minimal.pdf", '@file.pdf'); | |
| 36 | +$td->runtest("\@file exists and file doesn't", | |
| 37 | + {$td->COMMAND => "qpdf --check \@file.pdf"}, | |
| 38 | + {$td->FILE => "check-at-file.out", $td->EXIT_STATUS => 0}, | |
| 39 | + $td->NORMALIZE_NEWLINES); | |
| 40 | +$td->runtest("missing underlay filename", | |
| 41 | + {$td->COMMAND => "qpdf --underlay --"}, | |
| 42 | + {$td->REGEXP => ".*underlay file not specified.*", | |
| 43 | + $td->EXIT_STATUS => 2}, | |
| 44 | + $td->NORMALIZE_NEWLINES); | |
| 45 | +$td->runtest("extra overlay filename", | |
| 46 | + {$td->COMMAND => "qpdf --overlay x x --"}, | |
| 47 | + {$td->REGEXP => ".*overlay file already specified.*", | |
| 48 | + $td->EXIT_STATUS => 2}, | |
| 49 | + $td->NORMALIZE_NEWLINES); | |
| 50 | +$td->runtest("multiple pages options", | |
| 51 | + {$td->COMMAND => "qpdf --pages . --password=x -- --pages . --"}, | |
| 52 | + {$td->REGEXP => ".*--pages may only be specified one time.*", | |
| 53 | + $td->EXIT_STATUS => 2}, | |
| 54 | + $td->NORMALIZE_NEWLINES); | |
| 55 | +$td->runtest("bad numeric range detects unclosed --pages", | |
| 56 | + {$td->COMMAND => "qpdf --pages . --pages . --"}, | |
| 57 | + {$td->REGEXP => ".*pages options must be terminated with --.*", | |
| 58 | + $td->EXIT_STATUS => 2}, | |
| 59 | + $td->NORMALIZE_NEWLINES); | |
| 60 | +$td->runtest("bad file detected as unclosed --pages", | |
| 61 | + {$td->COMMAND => "qpdf --pages . 1 --xyz out"}, | |
| 62 | + {$td->REGEXP => ".*pages options must be terminated with --.*", | |
| 63 | + $td->EXIT_STATUS => 2}, | |
| 64 | + $td->NORMALIZE_NEWLINES); | |
| 65 | +$td->runtest("misplaced pages password 1", | |
| 66 | + {$td->COMMAND => "qpdf --pages . 1 --password=z --"}, | |
| 67 | + {$td->REGEXP => ".*password must immediately follow a file name.*", | |
| 68 | + $td->EXIT_STATUS => 2}, | |
| 69 | + $td->NORMALIZE_NEWLINES); | |
| 70 | +$td->runtest("misplaced pages password 2", | |
| 71 | + {$td->COMMAND => "qpdf --pages --password=z . 1 --"}, | |
| 72 | + {$td->REGEXP => ".*password must immediately follow a file name.*", | |
| 73 | + $td->EXIT_STATUS => 2}, | |
| 74 | + $td->NORMALIZE_NEWLINES); | |
| 75 | +$td->runtest("duplicated pages password", | |
| 76 | + {$td->COMMAND => "qpdf --pages . --password=z --password=z --"}, | |
| 77 | + {$td->REGEXP => ".*password already specified.*", | |
| 78 | + $td->EXIT_STATUS => 2}, | |
| 79 | + $td->NORMALIZE_NEWLINES); | |
| 80 | +# Ignoring -- at the top level was never intended but turned out to | |
| 81 | +# have been there for a long time so that people relied on it. It is | |
| 82 | +# intentionally not documented. | |
| 83 | +$td->runtest("ignore -- at top level", | |
| 84 | + {$td->COMMAND => "qpdf -- --check -- minimal.pdf --"}, | |
| 85 | + {$td->REGEXP => ".*No syntax or stream encoding errors found.*", | |
| 86 | + $td->EXIT_STATUS => 0}, | |
| 87 | + $td->NORMALIZE_NEWLINES); | |
| 88 | + | |
| 89 | +cleanup(); | |
| 90 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/attachments.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('attachments'); | |
| 16 | + | |
| 17 | +my $n_tests = 37; | |
| 18 | + | |
| 19 | +open(F, ">auto-txt") or die; | |
| 20 | +print F "from file"; | |
| 21 | +close(F); | |
| 22 | +$td->runtest("attachments", | |
| 23 | + {$td->COMMAND => "test_driver 76 minimal.pdf auto-txt"}, | |
| 24 | + {$td->FILE => "test76.out", $td->EXIT_STATUS => 0}, | |
| 25 | + $td->NORMALIZE_NEWLINES); | |
| 26 | +$td->runtest("show attachment", | |
| 27 | + {$td->COMMAND => "qpdf --show-attachment=att1 a.pdf"}, | |
| 28 | + {$td->STRING => "from file", $td->EXIT_STATUS => 0}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | +$td->runtest("check output", | |
| 31 | + {$td->FILE => "a.pdf"}, | |
| 32 | + {$td->FILE => "test76.pdf"}); | |
| 33 | +$td->runtest("list attachments", | |
| 34 | + {$td->COMMAND => "qpdf --list-attachments a.pdf"}, | |
| 35 | + {$td->FILE => "test76-list.out", $td->EXIT_STATUS => 0}, | |
| 36 | + $td->NORMALIZE_NEWLINES); | |
| 37 | +$td->runtest("list attachments verbose", | |
| 38 | + {$td->COMMAND => "qpdf --list-attachments --verbose a.pdf"}, | |
| 39 | + {$td->FILE => "test76-list-verbose.out", $td->EXIT_STATUS => 0}, | |
| 40 | + $td->NORMALIZE_NEWLINES); | |
| 41 | +$td->runtest("attachments json", | |
| 42 | + {$td->COMMAND => "qpdf --json=1 --json-key=attachments a.pdf"}, | |
| 43 | + {$td->FILE => "test76-json.out", $td->EXIT_STATUS => 0}, | |
| 44 | + $td->NORMALIZE_NEWLINES); | |
| 45 | +$td->runtest("remove attachment (test_driver)", | |
| 46 | + {$td->COMMAND => "test_driver 77 test76.pdf"}, | |
| 47 | + {$td->STRING => "test 77 done\n", $td->EXIT_STATUS => 0}, | |
| 48 | + $td->NORMALIZE_NEWLINES); | |
| 49 | +$td->runtest("check output", | |
| 50 | + {$td->FILE => "a.pdf"}, | |
| 51 | + {$td->FILE => "test77.pdf"}); | |
| 52 | +$td->runtest("remove attachment (cli)", | |
| 53 | + {$td->COMMAND => "qpdf --remove-attachment=att2 test76.pdf" . | |
| 54 | + " --static-id --qdf --verbose b.pdf"}, | |
| 55 | + {$td->FILE => "remove-attachment.out", $td->EXIT_STATUS => 0}, | |
| 56 | + $td->NORMALIZE_NEWLINES); | |
| 57 | +$td->runtest("check output", | |
| 58 | + {$td->FILE => "b.pdf"}, | |
| 59 | + {$td->FILE => "test77.pdf"}); | |
| 60 | +$td->runtest("show missing attachment", | |
| 61 | + {$td->COMMAND => "qpdf --show-attachment=att2 b.pdf"}, | |
| 62 | + {$td->STRING => "qpdf: attachment att2 not found\n", | |
| 63 | + $td->EXIT_STATUS => 2}, | |
| 64 | + $td->NORMALIZE_NEWLINES); | |
| 65 | +$td->runtest("remove missing attachment", | |
| 66 | + {$td->COMMAND => "qpdf --remove-attachment=att2 b.pdf c.pdf"}, | |
| 67 | + {$td->STRING => "qpdf: attachment att2 not found\n", | |
| 68 | + $td->EXIT_STATUS => 2}, | |
| 69 | + $td->NORMALIZE_NEWLINES); | |
| 70 | + | |
| 71 | +$td->runtest("add attachment: bad creation date", | |
| 72 | + {$td->COMMAND => "qpdf minimal.pdf a.pdf" . | |
| 73 | + " --add-attachment auto-txt --creationdate=potato --"}, | |
| 74 | + {$td->REGEXP => ".*potato is not a valid PDF timestamp.*", | |
| 75 | + $td->EXIT_STATUS => 2}, | |
| 76 | + $td->NORMALIZE_NEWLINES); | |
| 77 | +$td->runtest("add attachment: bad mod date", | |
| 78 | + {$td->COMMAND => "qpdf minimal.pdf a.pdf" . | |
| 79 | + " --add-attachment auto-txt --moddate=potato --"}, | |
| 80 | + {$td->REGEXP => ".*potato is not a valid PDF timestamp.*", | |
| 81 | + $td->EXIT_STATUS => 2}, | |
| 82 | + $td->NORMALIZE_NEWLINES); | |
| 83 | +$td->runtest("add attachment: bad mod date", | |
| 84 | + {$td->COMMAND => "qpdf minimal.pdf a.pdf" . | |
| 85 | + " --add-attachment auto-txt --mimetype=potato --"}, | |
| 86 | + {$td->REGEXP => | |
| 87 | + ".*mime type should be specified as type/subtype.*", | |
| 88 | + $td->EXIT_STATUS => 2}, | |
| 89 | + $td->NORMALIZE_NEWLINES); | |
| 90 | +$td->runtest("add attachment: trailing slash", | |
| 91 | + {$td->COMMAND => "qpdf minimal.pdf a.pdf" . | |
| 92 | + " --add-attachment --"}, | |
| 93 | + {$td->REGEXP => ".*add attachment: no file specified.*", | |
| 94 | + $td->EXIT_STATUS => 2}, | |
| 95 | + $td->NORMALIZE_NEWLINES); | |
| 96 | + | |
| 97 | +foreach my $i (qw(1 2 3)) | |
| 98 | +{ | |
| 99 | + open(F, ">auto-$i") or die; | |
| 100 | + print F "attachment $i"; | |
| 101 | + close(F); | |
| 102 | +} | |
| 103 | +my @dates = ("--creationdate=D:20210210091359-05'00'", | |
| 104 | + "--moddate=D:20210210141359Z"); | |
| 105 | +$td->runtest("add attachments", | |
| 106 | + {$td->COMMAND => | |
| 107 | + [qw(qpdf minimal.pdf a.pdf --no-original-object-ids), | |
| 108 | + qw(--verbose --static-id --qdf), | |
| 109 | + qw(--add-attachment ./auto-1), @dates, | |
| 110 | + qw(--mimetype=text/plain --), | |
| 111 | + qw(--add-attachment ./auto-2 --key=auto-Two), @dates, '--', | |
| 112 | + qw(--add-attachment ./auto-3 --filename=auto-Three.txt), | |
| 113 | + @dates, '--description=two words', '--']}, | |
| 114 | + {$td->FILE => "add-attachments-1.out", $td->EXIT_STATUS => 0}, | |
| 115 | + $td->NORMALIZE_NEWLINES); | |
| 116 | +$td->runtest("list attachments", | |
| 117 | + {$td->COMMAND => "qpdf --list-attachments a.pdf --verbose"}, | |
| 118 | + {$td->FILE => "list-attachments-1.out", $td->EXIT_STATUS => 0}, | |
| 119 | + $td->NORMALIZE_NEWLINES); | |
| 120 | +$td->runtest("check output", | |
| 121 | + {$td->FILE => "a.pdf"}, | |
| 122 | + {$td->FILE => "add-attachments-1.pdf"}, | |
| 123 | + $td->NORMALIZE_NEWLINES); | |
| 124 | +$td->runtest("add attachments: duplicate", | |
| 125 | + {$td->COMMAND => | |
| 126 | + "qpdf a.pdf b.pdf --verbose --add-attachment ./auto-1 --"}, | |
| 127 | + {$td->FILE => "add-attachments-duplicate.out", | |
| 128 | + $td->EXIT_STATUS => 2}, | |
| 129 | + $td->NORMALIZE_NEWLINES); | |
| 130 | +$td->runtest("add attachments: replace", | |
| 131 | + {$td->COMMAND => | |
| 132 | + [qw(qpdf a.pdf b.pdf --no-original-object-ids), | |
| 133 | + qw(--verbose --static-id --qdf), | |
| 134 | + qw(--add-attachment ./auto-2 --key=auto-1 --replace), | |
| 135 | + @dates, '--']}, | |
| 136 | + {$td->FILE => "add-attachments-2.out", $td->EXIT_STATUS => 0}, | |
| 137 | + $td->NORMALIZE_NEWLINES); | |
| 138 | +$td->runtest("list attachments", | |
| 139 | + {$td->COMMAND => "qpdf --list-attachments b.pdf --verbose"}, | |
| 140 | + {$td->FILE => "list-attachments-3.out", $td->EXIT_STATUS => 0}, | |
| 141 | + $td->NORMALIZE_NEWLINES); | |
| 142 | +$td->runtest("check output", | |
| 143 | + {$td->FILE => "b.pdf"}, | |
| 144 | + {$td->FILE => "add-attachments-2.pdf"}, | |
| 145 | + $td->NORMALIZE_NEWLINES); | |
| 146 | +$td->runtest("copy attachments", | |
| 147 | + {$td->COMMAND => | |
| 148 | + "qpdf --verbose --no-original-object-ids" . | |
| 149 | + " --static-id --qdf minimal.pdf b.pdf" . | |
| 150 | + " --copy-attachments-from a.pdf --"}, | |
| 151 | + {$td->FILE => "copy-attachments-1.out", $td->EXIT_STATUS => 0}, | |
| 152 | + $td->NORMALIZE_NEWLINES); | |
| 153 | +$td->runtest("list attachments", | |
| 154 | + {$td->COMMAND => "qpdf --list-attachments b.pdf --verbose"}, | |
| 155 | + {$td->FILE => "list-attachments-1.out", $td->EXIT_STATUS => 0}, | |
| 156 | + $td->NORMALIZE_NEWLINES); | |
| 157 | +$td->runtest("check output", | |
| 158 | + {$td->FILE => "b.pdf"}, | |
| 159 | + {$td->FILE => "add-attachments-1.pdf"}, | |
| 160 | + $td->NORMALIZE_NEWLINES); | |
| 161 | +$td->runtest("copy attachments: duplicate", | |
| 162 | + {$td->COMMAND => | |
| 163 | + "qpdf --verbose --no-original-object-ids" . | |
| 164 | + " --static-id --qdf a.pdf c.pdf" . | |
| 165 | + " --copy-attachments-from b.pdf --"}, | |
| 166 | + {$td->FILE => "copy-attachments-duplicate.out", | |
| 167 | + $td->EXIT_STATUS => 2}, | |
| 168 | + $td->NORMALIZE_NEWLINES); | |
| 169 | +$td->runtest("copy attachments: prefix", | |
| 170 | + {$td->COMMAND => | |
| 171 | + "qpdf --verbose --no-original-object-ids" . | |
| 172 | + " --static-id --qdf a.pdf c.pdf" . | |
| 173 | + " --copy-attachments-from b.pdf --prefix=1- --"}, | |
| 174 | + {$td->FILE => "copy-attachments-2.out", $td->EXIT_STATUS => 0}, | |
| 175 | + $td->NORMALIZE_NEWLINES); | |
| 176 | +$td->runtest("list attachments", | |
| 177 | + {$td->COMMAND => "qpdf --list-attachments c.pdf --verbose"}, | |
| 178 | + {$td->FILE => "list-attachments-2.out", $td->EXIT_STATUS => 0}, | |
| 179 | + $td->NORMALIZE_NEWLINES); | |
| 180 | +$td->runtest("check output", | |
| 181 | + {$td->FILE => "c.pdf"}, | |
| 182 | + {$td->FILE => "copy-attachments-2.pdf"}, | |
| 183 | + $td->NORMALIZE_NEWLINES); | |
| 184 | +$td->runtest("add attachments: current date", | |
| 185 | + {$td->COMMAND => | |
| 186 | + [qw(qpdf minimal.pdf a.pdf --encrypt u o 256 --), | |
| 187 | + qw(--verbose --add-attachment ./auto-1 --)]}, | |
| 188 | + {$td->FILE => "add-attachments-3.out", $td->EXIT_STATUS => 0}, | |
| 189 | + $td->NORMALIZE_NEWLINES); | |
| 190 | +$td->runtest("list attachments", | |
| 191 | + {$td->COMMAND => | |
| 192 | + "qpdf --password=u --list-attachments a.pdf --verbose"}, | |
| 193 | + {$td->FILE => "list-attachments-4.out", $td->EXIT_STATUS => 0}, | |
| 194 | + $td->NORMALIZE_NEWLINES); | |
| 195 | +# The object to show here is the one in list-attachments-4.out | |
| 196 | +$td->runtest("check dates", | |
| 197 | + {$td->COMMAND => "qpdf --show-object=6 a.pdf --password=u"}, | |
| 198 | + {$td->REGEXP => ".*CreationDate \\(D:\\d+.*ModDate \\(D:\\d+.*", | |
| 199 | + $td->EXIT_STATUS => 0}, | |
| 200 | + $td->NORMALIZE_NEWLINES); | |
| 201 | +$td->runtest("remove multiple attachments", | |
| 202 | + {$td->COMMAND => | |
| 203 | + "qpdf --verbose --static-id add-attachments-1.pdf a.pdf" . | |
| 204 | + " --remove-attachment=auto-1 --remove-attachment=auto-Two"}, | |
| 205 | + {$td->FILE => "remove-multiple-attachments.out", | |
| 206 | + $td->EXIT_STATUS => 0}, | |
| 207 | + $td->NORMALIZE_NEWLINES); | |
| 208 | +$td->runtest("check output", | |
| 209 | + {$td->FILE => "a.pdf"}, | |
| 210 | + {$td->FILE => "remove-multiple-attachments.pdf"}); | |
| 211 | +$td->runtest("remove multiple attachments (json)", | |
| 212 | + {$td->COMMAND => | |
| 213 | + "qpdf --job-json-file=remove-multiple-attachments.json"}, | |
| 214 | + {$td->FILE => "remove-multiple-attachments-json.out", | |
| 215 | + $td->EXIT_STATUS => 0}, | |
| 216 | + $td->NORMALIZE_NEWLINES); | |
| 217 | +$td->runtest("check output", | |
| 218 | + {$td->FILE => "b.pdf"}, | |
| 219 | + {$td->FILE => "remove-multiple-attachments.pdf"}); | |
| 220 | + | |
| 221 | +cleanup(); | |
| 222 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/basic_parsing.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('basic_parsing'); | |
| 16 | + | |
| 17 | +my @goodfiles = ("implicit null", # 1 | |
| 18 | + "direct null", # 2 | |
| 19 | + "unresolved null", # 3 | |
| 20 | + "indirect null", # 4 | |
| 21 | + "indirect bool, real", # 5 | |
| 22 | + "direct bool", # 6 | |
| 23 | + "integer", # 7 | |
| 24 | + "real, ASCIIHexDecode", # 8 | |
| 25 | + "string", # 9 | |
| 26 | + "array", # 10 | |
| 27 | + "dictionary", # 11 | |
| 28 | + "stream", # 12 | |
| 29 | + "nesting, strings, names", # 13 | |
| 30 | + "tokenizing pipeline", # 14 | |
| 31 | + "name", # 15 | |
| 32 | + "object-stream", # 16 | |
| 33 | + "hybrid xref", # 17 | |
| 34 | + "hybrid xref old mode", # 18 | |
| 35 | + "xref with prev", # 19 | |
| 36 | + "lots of compressible objects", # 20 | |
| 37 | + "array with indirect nulls", # 21 | |
| 38 | + ); | |
| 39 | + | |
| 40 | +my $n_tests = (3 * @goodfiles) + 6; | |
| 41 | + | |
| 42 | +my %goodtest_overrides = ('14' => 3); | |
| 43 | +my %goodtest_flags = | |
| 44 | + ('18' => '-ignore-xref-streams', | |
| 45 | + '20' => '-object-streams=generate', | |
| 46 | + ); | |
| 47 | +for (my $i = 1; $i <= scalar(@goodfiles); ++$i) | |
| 48 | +{ | |
| 49 | + my $n = $goodtest_overrides{$i} || 1; | |
| 50 | + $td->runtest("$goodfiles[$i-1]", | |
| 51 | + {$td->COMMAND => "test_driver $n good$i.pdf"}, | |
| 52 | + {$td->FILE => "good$i.out", | |
| 53 | + $td->EXIT_STATUS => 0}, | |
| 54 | + $td->NORMALIZE_NEWLINES); | |
| 55 | + my $xflags = $goodtest_flags{$i} || ''; | |
| 56 | + check_pdf($td, "create qdf", | |
| 57 | + "qpdf --static-id -qdf $xflags good$i.pdf", | |
| 58 | + "good$i.qdf", 0); | |
| 59 | +} | |
| 60 | + | |
| 61 | +check_pdf($td, "no normalization", | |
| 62 | + "qpdf -qdf --static-id --normalize-content=n good7.pdf", | |
| 63 | + "good7-not-normalized.qdf", | |
| 64 | + 0); | |
| 65 | + | |
| 66 | +check_pdf($td, "no qdf", | |
| 67 | + "qpdf --static-id good17.pdf", | |
| 68 | + "good17-not-qdf.pdf", | |
| 69 | + 0); | |
| 70 | + | |
| 71 | +check_pdf($td, "no recompression", | |
| 72 | + "qpdf --static-id --stream-data=preserve good17.pdf", | |
| 73 | + "good17-not-recompressed.pdf", | |
| 74 | + 0); | |
| 75 | + | |
| 76 | +cleanup(); | |
| 77 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/bound_checks.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('bound_checks'); | |
| 16 | + | |
| 17 | +my $n_tests = 3; | |
| 18 | + | |
| 19 | +$td->runtest("bounds check linearization data 1", | |
| 20 | + {$td->COMMAND => "qpdf --check linearization-bounds-1.pdf"}, | |
| 21 | + {$td->FILE => "linearization-bounds-1.out", | |
| 22 | + $td->EXIT_STATUS => 3}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | +$td->runtest("bounds check linearization data 2", | |
| 25 | + {$td->COMMAND => "qpdf --check linearization-bounds-2.pdf"}, | |
| 26 | + {$td->FILE => "linearization-bounds-2.out", | |
| 27 | + $td->EXIT_STATUS => 3}, | |
| 28 | + $td->NORMALIZE_NEWLINES); | |
| 29 | +# Throws runtime error, not bad_alloc | |
| 30 | +$td->runtest("sanity check array size", | |
| 31 | + {$td->COMMAND => | |
| 32 | + "qpdf --check linearization-large-vector-alloc.pdf"}, | |
| 33 | + {$td->FILE => "linearization-large-vector-alloc.out", | |
| 34 | + $td->EXIT_STATUS => 3}, | |
| 35 | + $td->NORMALIZE_NEWLINES); | |
| 36 | + | |
| 37 | +cleanup(); | |
| 38 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/c_api.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('c_api'); | |
| 16 | + | |
| 17 | +my @capi = ( | |
| 18 | + [2, 'no options'], | |
| 19 | + [3, 'normalized content'], | |
| 20 | + [4, 'ignore xref streams'], | |
| 21 | + [5, 'linearized'], | |
| 22 | + [6, 'object streams'], | |
| 23 | + [7, 'qdf'], | |
| 24 | + [8, 'no original object ids'], | |
| 25 | + [9, 'uncompressed streams'], | |
| 26 | + ); | |
| 27 | +my $n_tests = (2 * @capi) + 5; | |
| 28 | +foreach my $d (@capi) | |
| 29 | +{ | |
| 30 | + my ($n, $description) = @$d; | |
| 31 | + my $outfile = $description; | |
| 32 | + $outfile =~ s/ /-/g; | |
| 33 | + $outfile = "c-$outfile.pdf"; | |
| 34 | + $td->runtest($description, | |
| 35 | + {$td->COMMAND => "qpdf-ctest $n hybrid-xref.pdf '' a.pdf"}, | |
| 36 | + {$td->STRING => "C test $n done\n", $td->EXIT_STATUS => 0}, | |
| 37 | + $td->NORMALIZE_NEWLINES); | |
| 38 | + $td->runtest("check $description", | |
| 39 | + {$td->FILE => "a.pdf"}, | |
| 40 | + {$td->FILE => $outfile}); | |
| 41 | +} | |
| 42 | +$td->runtest("write to bad file name", | |
| 43 | + {$td->COMMAND => "qpdf-ctest 2 hybrid-xref.pdf '' /:a:/:b:"}, | |
| 44 | + {$td->REGEXP => "error: open /:a:/:b:: .*", | |
| 45 | + $td->EXIT_STATUS => 0}, | |
| 46 | + $td->NORMALIZE_NEWLINES); | |
| 47 | + | |
| 48 | +$td->runtest("write damaged to bad file name", | |
| 49 | + {$td->COMMAND => "qpdf-ctest 2 append-page-content-damaged.pdf" . | |
| 50 | + " '' /:a:/:b:"}, | |
| 51 | + {$td->REGEXP => | |
| 52 | + "warning:(?s:.*)\n" . | |
| 53 | + "error: open /:a:/:b:: .*", | |
| 54 | + $td->EXIT_STATUS => 0}, | |
| 55 | + $td->NORMALIZE_NEWLINES); | |
| 56 | + | |
| 57 | +$td->runtest("write damaged", | |
| 58 | + {$td->COMMAND => "qpdf-ctest 2 append-page-content-damaged.pdf" . | |
| 59 | + " '' a.pdf"}, | |
| 60 | + {$td->FILE => "c-write-damaged.out", | |
| 61 | + $td->EXIT_STATUS => 0}, | |
| 62 | + $td->NORMALIZE_NEWLINES); | |
| 63 | + | |
| 64 | +$td->runtest("empty PDF", | |
| 65 | + {$td->COMMAND => "qpdf-ctest 41 - '' a.pdf"}, | |
| 66 | + {$td->STRING => "C test 41 done\n", $td->EXIT_STATUS => 0}, | |
| 67 | + $td->NORMALIZE_NEWLINES); | |
| 68 | +$td->runtest("check output", | |
| 69 | + {$td->FILE => "a.pdf"}, | |
| 70 | + {$td->FILE => "c-empty.pdf"}); | |
| 71 | + | |
| 72 | +cleanup(); | |
| 73 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/c_api_check.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('c_api_check'); | |
| 16 | + | |
| 17 | +my @c_check_types = qw(warn clear); | |
| 18 | +my $n_tests = scalar(@c_check_types); | |
| 19 | + | |
| 20 | +foreach my $i (@c_check_types) | |
| 21 | +{ | |
| 22 | + $td->runtest("C check $i", | |
| 23 | + {$td->COMMAND => "qpdf-ctest 23 c-check-$i-in.pdf '' -"}, | |
| 24 | + {$td->FILE => "c-check-$i.out", | |
| 25 | + $td->EXIT_STATUS => 0}, | |
| 26 | + $td->NORMALIZE_NEWLINES); | |
| 27 | +} | |
| 28 | + | |
| 29 | +cleanup(); | |
| 30 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/c_api_key.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('c_api_key'); | |
| 16 | + | |
| 17 | +my $n_tests = 4; | |
| 18 | + | |
| 19 | +$td->runtest("C API info key functions", | |
| 20 | + {$td->COMMAND => "qpdf-ctest 16 minimal.pdf '' a.pdf"}, | |
| 21 | + {$td->FILE => "c-info1.out", | |
| 22 | + $td->EXIT_STATUS => 0}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | +$td->runtest("check output", | |
| 25 | + {$td->FILE => "a.pdf"}, | |
| 26 | + {$td->FILE => "c-info-out.pdf"}); | |
| 27 | +unlink "a.pdf" or die; | |
| 28 | + | |
| 29 | +$td->runtest("C API info key functions", | |
| 30 | + {$td->COMMAND => "qpdf-ctest 16 c-info2-in.pdf '' a.pdf"}, | |
| 31 | + {$td->FILE => "c-info2.out", | |
| 32 | + $td->EXIT_STATUS => 0}, | |
| 33 | + $td->NORMALIZE_NEWLINES); | |
| 34 | +$td->runtest("check output", | |
| 35 | + {$td->FILE => "a.pdf"}, | |
| 36 | + {$td->FILE => "c-info-out.pdf"}); | |
| 37 | +unlink "a.pdf" or die; | |
| 38 | + | |
| 39 | +cleanup(); | |
| 40 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/c_api_object_handle.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('c_api_object_handle'); | |
| 16 | + | |
| 17 | +my $n_tests = 13; | |
| 18 | + | |
| 19 | +$td->runtest("C check object handles", | |
| 20 | + {$td->COMMAND => "qpdf-ctest 24 minimal.pdf '' a.pdf"}, | |
| 21 | + {$td->FILE => "c-object-handles.out", | |
| 22 | + $td->EXIT_STATUS => 0}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | +$td->runtest("check output", | |
| 25 | + {$td->FILE => 'a.pdf'}, | |
| 26 | + {$td->FILE => 'c-object-handles-out.pdf'}); | |
| 27 | + | |
| 28 | +$td->runtest("C check object handle creation", | |
| 29 | + {$td->COMMAND => "qpdf-ctest 25 minimal.pdf '' a.pdf"}, | |
| 30 | + {$td->STRING => "C test 25 done\n", $td->EXIT_STATUS => 0}, | |
| 31 | + $td->NORMALIZE_NEWLINES); | |
| 32 | +$td->runtest("check output", | |
| 33 | + {$td->FILE => 'a.pdf'}, | |
| 34 | + {$td->FILE => 'c-object-handle-creation-out.pdf'}); | |
| 35 | + | |
| 36 | +$td->runtest("C indirect objects", | |
| 37 | + {$td->COMMAND => "qpdf-ctest 33 minimal.pdf '' a.pdf"}, | |
| 38 | + {$td->STRING => "C test 33 done\n", $td->EXIT_STATUS => 0}, | |
| 39 | + $td->NORMALIZE_NEWLINES); | |
| 40 | +$td->runtest("check output", | |
| 41 | + {$td->FILE => 'a.pdf'}, | |
| 42 | + {$td->FILE => 'c-indirect-objects-out.pdf'}); | |
| 43 | + | |
| 44 | +$td->runtest("C uninitialized objects", | |
| 45 | + {$td->COMMAND => "qpdf-ctest 26 '' '' ''"}, | |
| 46 | + {$td->FILE => "c-oh-uninitialized-objects.out", | |
| 47 | + $td->EXIT_STATUS => 0}, | |
| 48 | + $td->NORMALIZE_NEWLINES); | |
| 49 | +$td->runtest("C string with embedded null", | |
| 50 | + {$td->COMMAND => "qpdf-ctest 27 '' '' ''"}, | |
| 51 | + {$td->STRING => "C test 27 done\n", $td->EXIT_STATUS => 0}, | |
| 52 | + $td->NORMALIZE_NEWLINES); | |
| 53 | +$td->runtest("C wrap and clone objects", | |
| 54 | + {$td->COMMAND => "qpdf-ctest 28 minimal.pdf '' ''"}, | |
| 55 | + {$td->STRING => "C test 28 done\n", $td->EXIT_STATUS => 0}, | |
| 56 | + $td->NORMALIZE_NEWLINES); | |
| 57 | +$td->runtest("C object handle errors", | |
| 58 | + {$td->COMMAND => "qpdf-ctest 29 minimal.pdf '' ''"}, | |
| 59 | + {$td->FILE => "c-oh-errors.out", $td->EXIT_STATUS => 0}, | |
| 60 | + $td->NORMALIZE_NEWLINES); | |
| 61 | +$td->runtest("C unhandled error warning", | |
| 62 | + {$td->COMMAND => "qpdf-ctest 30 bad1.pdf '' ''"}, | |
| 63 | + {$td->FILE => "c-unhandled-error.out", $td->EXIT_STATUS => 0}, | |
| 64 | + $td->NORMALIZE_NEWLINES); | |
| 65 | +$td->runtest("C type mismatch warning", | |
| 66 | + {$td->COMMAND => "qpdf-ctest 31 minimal.pdf '' ''"}, | |
| 67 | + {$td->FILE => "c-type-warning.out", $td->EXIT_STATUS => 0}, | |
| 68 | + $td->NORMALIZE_NEWLINES); | |
| 69 | +$td->runtest("C get object by ID", | |
| 70 | + {$td->COMMAND => "qpdf-ctest 32 minimal.pdf '' ''"}, | |
| 71 | + {$td->STRING => "C test 32 done\n", $td->EXIT_STATUS => 0}, | |
| 72 | + $td->NORMALIZE_NEWLINES); | |
| 73 | + | |
| 74 | +cleanup(); | |
| 75 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/c_api_page.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('c_api_page'); | |
| 16 | + | |
| 17 | +my $n_tests = 5; | |
| 18 | + | |
| 19 | +$td->runtest("C page normal", | |
| 20 | + {$td->COMMAND => | |
| 21 | + "qpdf-ctest 34 11-pages.pdf '' a.pdf minimal.pdf"}, | |
| 22 | + {$td->STRING => "C test 34 done\n", $td->EXIT_STATUS => 0}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | +$td->runtest("check output", | |
| 25 | + {$td->FILE => 'a.pdf'}, | |
| 26 | + {$td->FILE => 'c-pages.pdf'}); | |
| 27 | + | |
| 28 | +$td->runtest("C page errors", | |
| 29 | + {$td->COMMAND => | |
| 30 | + "qpdf-ctest 35 11-pages.pdf '' ''"}, | |
| 31 | + {$td->FILE => "c-page-errors.out", $td->EXIT_STATUS => 0}, | |
| 32 | + $td->NORMALIZE_NEWLINES); | |
| 33 | +$td->runtest("C inherited page resources", | |
| 34 | + {$td->COMMAND => | |
| 35 | + "qpdf-ctest 36 inherited-rotate.pdf '' ''"}, | |
| 36 | + {$td->STRING => "C test 36 done\n", $td->EXIT_STATUS => 0}, | |
| 37 | + $td->NORMALIZE_NEWLINES); | |
| 38 | +$td->runtest("C pages cache", | |
| 39 | + {$td->COMMAND => | |
| 40 | + "qpdf-ctest 37 11-pages.pdf '' ''"}, | |
| 41 | + {$td->STRING => "C test 37 done\n", $td->EXIT_STATUS => 0}, | |
| 42 | + $td->NORMALIZE_NEWLINES); | |
| 43 | + | |
| 44 | +cleanup(); | |
| 45 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/c_api_stream.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('c_api_stream'); | |
| 16 | + | |
| 17 | +my $n_tests = 5; | |
| 18 | + | |
| 19 | +$td->runtest("C read streams", | |
| 20 | + {$td->COMMAND => | |
| 21 | + "qpdf-ctest 38 11-pages.pdf '' ''"}, | |
| 22 | + {$td->FILE => "c-get-stream.out", $td->EXIT_STATUS => 0}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | + | |
| 25 | +$td->runtest("C foreign object", | |
| 26 | + {$td->COMMAND => | |
| 27 | + "qpdf-ctest 39 11-pages.pdf '' a.pdf minimal.pdf"}, | |
| 28 | + {$td->STRING => "C test 39 done\n", $td->EXIT_STATUS => 0}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | +$td->runtest("check output", | |
| 31 | + {$td->FILE => 'a.pdf'}, | |
| 32 | + {$td->FILE => 'c-foreign.pdf'}); | |
| 33 | + | |
| 34 | +$td->runtest("C new stream", | |
| 35 | + {$td->COMMAND => | |
| 36 | + "qpdf-ctest 40 minimal.pdf '' a.pdf"}, | |
| 37 | + {$td->STRING => "C test 40 done\n", $td->EXIT_STATUS => 0}, | |
| 38 | + $td->NORMALIZE_NEWLINES); | |
| 39 | +$td->runtest("check output", | |
| 40 | + {$td->FILE => 'a.pdf'}, | |
| 41 | + {$td->FILE => 'c-new-stream.pdf'}); | |
| 42 | +cleanup(); | |
| 43 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/character_encoding.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('character_encoding'); | |
| 16 | + | |
| 17 | +my $n_tests = 4; | |
| 18 | + | |
| 19 | +$td->runtest("PDF doc encoding to Unicode", | |
| 20 | + {$td->COMMAND => "test_pdf_doc_encoding pdf-doc-to-utf8.in"}, | |
| 21 | + {$td->FILE => "pdf-doc-to-utf8.out", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("UTF-16 encoding", | |
| 24 | + {$td->COMMAND => "test_pdf_unicode unicode.in"}, | |
| 25 | + {$td->FILE => "unicode.out", $td->EXIT_STATUS => 0}, | |
| 26 | + $td->NORMALIZE_NEWLINES); | |
| 27 | +$td->runtest("UTF-16 encoding errors", | |
| 28 | + {$td->COMMAND => "test_pdf_unicode unicode-errors.in"}, | |
| 29 | + {$td->FILE => "unicode-errors.out", $td->EXIT_STATUS => 0}, | |
| 30 | + $td->NORMALIZE_NEWLINES); | |
| 31 | + | |
| 32 | +# UTF-16LE is not allowed by the PDF spec, but it seems that most | |
| 33 | +# readers accept it. | |
| 34 | +$td->runtest("UTF-16LE strings", | |
| 35 | + {$td->COMMAND => "qpdf --list-attachments --verbose utf16le.pdf"}, | |
| 36 | + {$td->FILE => "utf16le-attachments.out", $td->EXIT_STATUS => 0}, | |
| 37 | + $td->NORMALIZE_NEWLINES); | |
| 38 | + | |
| 39 | +cleanup(); | |
| 40 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/check_encryption.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('check_encryption'); | |
| 16 | + | |
| 17 | +my @check_encryption_password = ( | |
| 18 | + # file, password, is-encrypted, requires-password | |
| 19 | + ["minimal.pdf", "", 2, 2], | |
| 20 | + ["20-pages.pdf", "", 0, 0], | |
| 21 | + ["20-pages.pdf", "user", 0, 3], | |
| 22 | + ); | |
| 23 | +my $n_tests = 3 * scalar(@check_encryption_password); | |
| 24 | +foreach my $d (@check_encryption_password) | |
| 25 | +{ | |
| 26 | + my ($file, $pass, $is_encrypted, $requires_password) = @$d; | |
| 27 | + $td->runtest("is encrypted ($file, pass=$pass)", | |
| 28 | + {$td->COMMAND => "qpdf --is-encrypted --password=$pass $file"}, | |
| 29 | + {$td->STRING => "", $td->EXIT_STATUS => $is_encrypted}); | |
| 30 | + $td->runtest("requires password ($file, pass=$pass)", | |
| 31 | + {$td->COMMAND => "qpdf --requires-password" . | |
| 32 | + " --password=$pass $file"}, | |
| 33 | + {$td->STRING => "", $td->EXIT_STATUS => $requires_password}); | |
| 34 | +} | |
| 35 | + | |
| 36 | +# Exercise reading password from file | |
| 37 | +open(F, ">args") or die; | |
| 38 | +print F "user\n"; | |
| 39 | +close(F); | |
| 40 | +$td->runtest("password from file)", | |
| 41 | + {$td->COMMAND => "qpdf --check --password-file=args 20-pages.pdf"}, | |
| 42 | + {$td->FILE => "20-pages-check.out", $td->EXIT_STATUS => 0}, | |
| 43 | + $td->NORMALIZE_NEWLINES); | |
| 44 | +open(F, ">>args") or die; | |
| 45 | +print F "ignored\n"; | |
| 46 | +close(F); | |
| 47 | +$td->runtest("ignore extra args from file)", | |
| 48 | + {$td->COMMAND => "qpdf --check --password-file=args 20-pages.pdf"}, | |
| 49 | + {$td->FILE => "20-pages-check-password-warning.out", | |
| 50 | + $td->EXIT_STATUS => 0}, | |
| 51 | + $td->NORMALIZE_NEWLINES); | |
| 52 | +unlink "args"; | |
| 53 | +$td->runtest("password from stdin)", | |
| 54 | + {$td->COMMAND => "echo user |" . | |
| 55 | + " qpdf --check --password-file=- 20-pages.pdf"}, | |
| 56 | + {$td->FILE => "20-pages-check.out", $td->EXIT_STATUS => 0}, | |
| 57 | + $td->NORMALIZE_NEWLINES); | |
| 58 | + | |
| 59 | +cleanup(); | |
| 60 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/cleartext_metadata.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('cleartext_metadata'); | |
| 16 | + | |
| 17 | +my $n_tests = 58; | |
| 18 | + | |
| 19 | +# args: file, exp_encrypted, exp_cleartext | |
| 20 | +check_metadata($td, "compressed-metadata.pdf", 0, 0); | |
| 21 | +check_metadata($td, "enc-base.pdf", 0, 1); | |
| 22 | + | |
| 23 | +foreach my $f (qw(compressed-metadata.pdf enc-base.pdf)) | |
| 24 | +{ | |
| 25 | + foreach my $w (qw(compress preserve)) | |
| 26 | + { | |
| 27 | + $td->runtest("$w streams ($f)", | |
| 28 | + {$td->COMMAND => "qpdf --stream-data=$w $f a.pdf"}, | |
| 29 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 30 | + check_metadata($td, "a.pdf", 0, 1); | |
| 31 | + $td->runtest("encrypt normally", | |
| 32 | + {$td->COMMAND => | |
| 33 | + "qpdf --allow-weak-crypto" . | |
| 34 | + " --encrypt '' o 128 -- a.pdf b.pdf"}, | |
| 35 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 36 | + check_metadata($td, "b.pdf", 1, 0); | |
| 37 | + unlink "b.pdf"; | |
| 38 | + $td->runtest("encrypt V4", | |
| 39 | + {$td->COMMAND => | |
| 40 | + "qpdf --allow-weak-crypto" . | |
| 41 | + " --encrypt '' o 128 --force-V4 -- a.pdf b.pdf"}, | |
| 42 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 43 | + check_metadata($td, "b.pdf", 1, 0); | |
| 44 | + unlink "b.pdf"; | |
| 45 | + $td->runtest("encrypt with cleartext metadata", | |
| 46 | + {$td->COMMAND => | |
| 47 | + "qpdf --allow-weak-crypto" . | |
| 48 | + " --encrypt '' o 128 --cleartext-metadata --" . | |
| 49 | + " a.pdf b.pdf"}, | |
| 50 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 51 | + check_metadata($td, "b.pdf", 1, 1); | |
| 52 | + $td->runtest("preserve encryption", | |
| 53 | + {$td->COMMAND => "qpdf b.pdf c.pdf"}, | |
| 54 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 55 | + check_metadata($td, "c.pdf", 1, 1); | |
| 56 | + unlink "b.pdf", "c.pdf"; | |
| 57 | + $td->runtest("encrypt with aes and cleartext metadata", | |
| 58 | + {$td->COMMAND => | |
| 59 | + "qpdf --encrypt '' o 128" . | |
| 60 | + " --cleartext-metadata --use-aes=y -- a.pdf b.pdf"}, | |
| 61 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 62 | + check_metadata($td, "b.pdf", 1, 1); | |
| 63 | + $td->runtest("preserve encryption", | |
| 64 | + {$td->COMMAND => "qpdf b.pdf c.pdf"}, | |
| 65 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 66 | + check_metadata($td, "c.pdf", 1, 1); | |
| 67 | + unlink "b.pdf", "c.pdf"; | |
| 68 | + } | |
| 69 | +} | |
| 70 | + | |
| 71 | +cleanup(); | |
| 72 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/coalesce_contents.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('coalesce_contents'); | |
| 16 | + | |
| 17 | +my $n_tests = 8; | |
| 18 | + | |
| 19 | +$td->runtest("qdf with normalize warnings", | |
| 20 | + {$td->COMMAND => | |
| 21 | + "qpdf --qdf --static-id split-tokens.pdf a.pdf"}, | |
| 22 | + {$td->FILE => "normalize-warnings.out", $td->EXIT_STATUS => 3}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | +$td->runtest("check output", | |
| 25 | + {$td->FILE => "a.pdf"}, | |
| 26 | + {$td->FILE => "split-tokens.qdf"}); | |
| 27 | +$td->runtest("coalesce to qdf", | |
| 28 | + {$td->COMMAND => | |
| 29 | + "qpdf --qdf --static-id coalesce.pdf a.pdf"}, | |
| 30 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 31 | + $td->NORMALIZE_NEWLINES); | |
| 32 | +$td->runtest("check output", | |
| 33 | + {$td->FILE => "a.pdf"}, | |
| 34 | + {$td->FILE => "coalesce.qdf"}); | |
| 35 | +$td->runtest("coalesce contents with qdf", | |
| 36 | + {$td->COMMAND => | |
| 37 | + "qpdf --qdf --static-id" . | |
| 38 | + " --coalesce-contents coalesce.pdf a.pdf"}, | |
| 39 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 40 | +$td->runtest("check output", | |
| 41 | + {$td->FILE => "a.pdf"}, | |
| 42 | + {$td->FILE => "coalesce-out.qdf"}); | |
| 43 | +$td->runtest("coalesce contents without qdf", | |
| 44 | + {$td->COMMAND => | |
| 45 | + "qpdf --static-id" . | |
| 46 | + " --coalesce-contents coalesce.pdf a.pdf"}, | |
| 47 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 48 | +$td->runtest("check output", | |
| 49 | + {$td->FILE => "a.pdf"}, | |
| 50 | + {$td->FILE => "coalesce-out.pdf"}); | |
| 51 | + | |
| 52 | +cleanup(); | |
| 53 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/collate.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('collate'); | |
| 16 | + | |
| 17 | +my @collate = ( | |
| 18 | + ["", "three-files", "collate-odd", | |
| 19 | + "collate-odd.pdf 1-5 minimal.pdf collate-even.pdf 7-1"], | |
| 20 | + [1, "three-files", "collate-odd", | |
| 21 | + "collate-odd.pdf 1-5 minimal.pdf collate-even.pdf 7-1"], | |
| 22 | + [2, "three-files-2", "collate-odd", | |
| 23 | + "collate-odd.pdf 1-5 minimal.pdf collate-even.pdf 7-1"], | |
| 24 | + ); | |
| 25 | +my $n_tests = 2 * scalar(@collate); | |
| 26 | + | |
| 27 | +foreach my $d (@collate) | |
| 28 | +{ | |
| 29 | + my ($n, $description, $first, $args) = @$d; | |
| 30 | + my $collate = '--collate'; | |
| 31 | + if ($n) | |
| 32 | + { | |
| 33 | + $collate .= "=$n"; | |
| 34 | + } | |
| 35 | + $td->runtest("collate pages: $description", | |
| 36 | + {$td->COMMAND => | |
| 37 | + "qpdf --qdf --static-id $collate $first.pdf" . | |
| 38 | + " --pages $args -- a.pdf"}, | |
| 39 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 40 | + $td->runtest("check output", | |
| 41 | + {$td->FILE => "a.pdf"}, | |
| 42 | + {$td->FILE => "$description-collate-out.pdf"}); | |
| 43 | +} | |
| 44 | + | |
| 45 | +cleanup(); | |
| 46 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/compare_pdfs.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | +use Digest::MD5; | |
| 6 | +use File::Copy; | |
| 7 | + | |
| 8 | +unshift(@INC, '.'); | |
| 9 | +require qpdf_test_helpers; | |
| 10 | + | |
| 11 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 12 | + | |
| 13 | +require TestDriver; | |
| 14 | + | |
| 15 | +cleanup(); | |
| 16 | + | |
| 17 | +my $td = new TestDriver('compare_pdfs'); | |
| 18 | + | |
| 19 | +my $n_compare_pdfs = 5; | |
| 20 | + | |
| 21 | +# Check compare_pdfs to make sure that it works properly. Each call | |
| 22 | +# to compare_pdfs is worth three test cases. | |
| 23 | +compare_pdfs($td, "p1-a-p2-b.pdf", "p1-a-p2-b.pdf"); | |
| 24 | +compare_pdfs($td, "p1-a.pdf", "p1-a.pdf"); | |
| 25 | +compare_pdfs($td, "p1-a.pdf", "p1-b.pdf", 1); | |
| 26 | +compare_pdfs($td, "p1-a.pdf", "p1-a-p2-b.pdf", 1); | |
| 27 | +compare_pdfs($td, "p1-a-p2-a.pdf", "p1-a-p2-b.pdf", 1); | |
| 28 | +flush_tiff_cache(); | |
| 29 | + | |
| 30 | +cleanup(); | |
| 31 | +$td->report(calc_ntests(0, $n_compare_pdfs)); | ... | ... |
qpdf/qtest/completion.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | +unshift(@INC, '../../libtests/qtest/arg_parser'); | |
| 9 | +require completion_helpers; | |
| 10 | + | |
| 11 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 12 | + | |
| 13 | +require TestDriver; | |
| 14 | + | |
| 15 | +cleanup(); | |
| 16 | + | |
| 17 | +my $td = new TestDriver('completion'); | |
| 18 | + | |
| 19 | +# Tests to exercise QPDFArgParser belong in arg_parser.test in | |
| 20 | +# libtests. These tests are supposed to be specific to the qpdf cli. | |
| 21 | +# Since they were written prior to moving QPDFArgParser into the | |
| 22 | +# library, there are several tests here that also exercise | |
| 23 | +# QPDFArgParser logic. | |
| 24 | +my @completion_tests = ( | |
| 25 | + ['', 0, 'bad-input-1'], | |
| 26 | + ['', 1, 'bad-input-2'], | |
| 27 | + ['', 2, 'bad-input-3'], | |
| 28 | + ['qpdf', 2, 'bad-input-4'], | |
| 29 | + ['qpdf ', undef, 'top'], | |
| 30 | + ['qpdf -', undef, 'top-arg'], | |
| 31 | + ['qpdf --enc', undef, 'enc'], | |
| 32 | + ['qpdf --encrypt ', undef, 'encrypt'], | |
| 33 | + ['qpdf --encrypt u ', undef, 'encrypt-u'], | |
| 34 | + ['qpdf --encrypt u o ', undef, 'encrypt-u-o'], | |
| 35 | + ['qpdf @encrypt-u o ', undef, 'encrypt-u-o'], | |
| 36 | + ['qpdf --encrypt u o 40 --', undef, 'encrypt-40'], | |
| 37 | + ['qpdf --encrypt u o 128 --', undef, 'encrypt-128'], | |
| 38 | + ['qpdf --encrypt u o 256 --', undef, 'encrypt-256'], | |
| 39 | + ['qpdf --encrypt u o bad --', undef, 'encrypt-bad'], | |
| 40 | + ['qpdf --split-pag', undef, 'split'], | |
| 41 | + ['qpdf --decode-l', undef, 'decode-l'], | |
| 42 | + ['qpdf --decode-lzzz', 15, 'decode-l'], | |
| 43 | + ['qpdf --decode-level=', undef, 'decode-level'], | |
| 44 | + ['qpdf --decode-level=g', undef, 'decode-level-g'], | |
| 45 | + ['qpdf --check -', undef, 'later-arg'], | |
| 46 | + ['qpdf infile outfile oops --ch', undef, 'usage-empty'], | |
| 47 | + ['qpdf --encrypt \'user " password\' ', undef, 'quoting'], | |
| 48 | + ['qpdf --encrypt \'user password\' ', undef, 'quoting'], | |
| 49 | + ['qpdf --encrypt "user password" ', undef, 'quoting'], | |
| 50 | + ['qpdf --encrypt "user pass\'word" ', undef, 'quoting'], | |
| 51 | + ['qpdf --encrypt user\ password ', undef, 'quoting'], | |
| 52 | + ); | |
| 53 | +my $n_tests = 2 * scalar(@completion_tests); | |
| 54 | +my $completion_filter = | |
| 55 | + "perl ../../../libtests/qtest/arg_parser/filter-completion.pl"; | |
| 56 | +foreach my $c (@completion_tests) | |
| 57 | +{ | |
| 58 | + my ($cmd, $point, $description) = @$c; | |
| 59 | + my $out = "completion-$description.out"; | |
| 60 | + my $zout = "completion-$description-zsh.out"; | |
| 61 | + if (! -f $zout) | |
| 62 | + { | |
| 63 | + $zout = $out; | |
| 64 | + } | |
| 65 | + $td->runtest("bash completion: $description", | |
| 66 | + {$td->COMMAND => [@{bash_completion("qpdf", $cmd, $point)}], | |
| 67 | + $td->FILTER => "$completion_filter $out"}, | |
| 68 | + {$td->FILE => "$out", $td->EXIT_STATUS => 0}, | |
| 69 | + $td->NORMALIZE_NEWLINES); | |
| 70 | + $td->runtest("zsh completion: $description", | |
| 71 | + {$td->COMMAND => [@{zsh_completion("qpdf", $cmd, $point)}], | |
| 72 | + $td->FILTER => "$completion_filter $zout"}, | |
| 73 | + {$td->FILE => "$zout", $td->EXIT_STATUS => 0}, | |
| 74 | + $td->NORMALIZE_NEWLINES); | |
| 75 | +} | |
| 76 | + | |
| 77 | +cleanup(); | |
| 78 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/compression_level.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('compression_level'); | |
| 16 | + | |
| 17 | +my $n_tests = 4; | |
| 18 | + | |
| 19 | +check_pdf($td, "recompress with level", | |
| 20 | + "qpdf --static-id --recompress-flate --compression-level=9" . | |
| 21 | + " --object-streams=generate minimal.pdf", | |
| 22 | + "minimal-9.pdf", 0); | |
| 23 | +check_pdf($td, "recompress with level", | |
| 24 | + "qpdf --static-id --recompress-flate --compression-level=1" . | |
| 25 | + " --object-streams=generate minimal.pdf", | |
| 26 | + "minimal-1.pdf", 0); | |
| 27 | + | |
| 28 | +cleanup(); | |
| 29 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/content_preservation.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | +use Digest::MD5; | |
| 6 | +use File::Basename; | |
| 7 | +use File::Copy; | |
| 8 | + | |
| 9 | +unshift(@INC, '.'); | |
| 10 | +require qpdf_test_helpers; | |
| 11 | + | |
| 12 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 13 | + | |
| 14 | +require TestDriver; | |
| 15 | + | |
| 16 | +cleanup(); | |
| 17 | + | |
| 18 | +my $td = new TestDriver('content_preservation'); | |
| 19 | + | |
| 20 | +my @files = ("encrypted-with-images.pdf", # encrypted | |
| 21 | + "inline-images.pdf", | |
| 22 | + "lin-special.pdf", | |
| 23 | + "object-stream.pdf", | |
| 24 | + "hybrid-xref.pdf"); | |
| 25 | +my @flags = (["-qdf", # 1 | |
| 26 | + "qdf"], | |
| 27 | + ["-qdf --normalize-content=n", # 2 | |
| 28 | + "qdf not normalized"], | |
| 29 | + ["-qdf --stream-data=preserve", # 3 | |
| 30 | + "qdf not uncompressed"], | |
| 31 | + ["-qdf --stream-data=preserve --normalize-content=n", # 4 | |
| 32 | + "qdf not normalized or uncompressed"], | |
| 33 | + ["--stream-data=uncompress", # 5 | |
| 34 | + "uncompresed"], | |
| 35 | + ["--normalize-content=y", # 6 | |
| 36 | + "normalized"], | |
| 37 | + ["--stream-data=uncompress --normalize-content=y", # 7 | |
| 38 | + "uncompressed and normalized"], | |
| 39 | + ["-decrypt", # 8 | |
| 40 | + "decrypted"], | |
| 41 | + ["-linearize", # 9 | |
| 42 | + "linearized"], | |
| 43 | + ["-allow-weak-crypto -encrypt \"\" owner 128 --", # 10 | |
| 44 | + "encrypted"], | |
| 45 | + ["-linearize -allow-weak-crypto -encrypt \"\" o 128 --", # 11 | |
| 46 | + "linearized and encrypted"], | |
| 47 | + ["", # 12 | |
| 48 | + "no arguments"], | |
| 49 | + ); | |
| 50 | + | |
| 51 | +my $n_tests = 1 + (@files * @flags * 2 * 3); | |
| 52 | +my $n_compare_pdfs = 1 + (@files * @flags * 2); | |
| 53 | + | |
| 54 | +foreach my $file (@files) | |
| 55 | +{ | |
| 56 | + my $base = basename($file, '.pdf'); | |
| 57 | + | |
| 58 | + foreach my $o (qw(disable generate)) | |
| 59 | + { | |
| 60 | + my $n = 0; | |
| 61 | + my $oflags = "--object-streams=$o"; | |
| 62 | + my $odescrip = "os:" . substr($o, 0, 1); | |
| 63 | + my $osuf = ($o eq 'generate' ? "-ogen" : ""); | |
| 64 | + foreach my $d (@flags) | |
| 65 | + { | |
| 66 | + my ($flags, $fdescrip) = @$d; | |
| 67 | + ++$n; | |
| 68 | + system("rm -f *.pnm"); | |
| 69 | + | |
| 70 | + $td->runtest("$file ($odescrip $fdescrip)", | |
| 71 | + {$td->COMMAND => "qpdf $flags $oflags $file a.pdf"}, | |
| 72 | + {$td->STRING => "", | |
| 73 | + $td->EXIT_STATUS => 0}); | |
| 74 | + | |
| 75 | + $td->runtest("check status", | |
| 76 | + {$td->COMMAND => "qpdf --check a.pdf"}, | |
| 77 | + {$td->FILE => "$base.$n$osuf.check", | |
| 78 | + $td->EXIT_STATUS => 0}, | |
| 79 | + $td->NORMALIZE_NEWLINES); | |
| 80 | + | |
| 81 | + $td->runtest("check with C API", | |
| 82 | + {$td->COMMAND => [qw(qpdf-ctest 1 a.pdf), "", ""]}, | |
| 83 | + {$td->FILE => "$base.$n$osuf.c-check", | |
| 84 | + $td->EXIT_STATUS => 0}, | |
| 85 | + $td->NORMALIZE_NEWLINES); | |
| 86 | + | |
| 87 | + compare_pdfs($td, $file, "a.pdf"); | |
| 88 | + } | |
| 89 | + flush_tiff_cache(); | |
| 90 | + } | |
| 91 | +} | |
| 92 | + | |
| 93 | +$td->runtest("convert inline-images to qdf", | |
| 94 | + {$td->COMMAND => "qpdf --static-id --no-original-object-ids" . | |
| 95 | + " --qdf inline-images.pdf a.pdf"}, | |
| 96 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 97 | + | |
| 98 | +compare_pdfs($td, "inline-images.pdf", "a.pdf"); | |
| 99 | + | |
| 100 | +cleanup(); | |
| 101 | +$td->report(calc_ntests($n_tests, $n_compare_pdfs)); | ... | ... |
qpdf/qtest/copy_annotations.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('copy_annotations'); | |
| 16 | + | |
| 17 | +my $n_tests = 39; | |
| 18 | + | |
| 19 | +$td->runtest("complex copy annotations", | |
| 20 | + {$td->COMMAND => | |
| 21 | + "qpdf --qdf --static-id --no-original-object-ids" . | |
| 22 | + " fxo-red.pdf --overlay form-fields-and-annotations.pdf" . | |
| 23 | + " --repeat=1 -- a.pdf"}, | |
| 24 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 25 | + $td->NORMALIZE_NEWLINES); | |
| 26 | +$td->runtest("check output", | |
| 27 | + {$td->FILE => "a.pdf"}, | |
| 28 | + {$td->FILE => "overlay-copy-annotations.pdf"}); | |
| 29 | + | |
| 30 | +foreach my $page (1, 2, 5, 6) | |
| 31 | +{ | |
| 32 | + $td->runtest("copy annotations single page ($page)", | |
| 33 | + {$td->COMMAND => | |
| 34 | + "qpdf --qdf --static-id --no-original-object-ids" . | |
| 35 | + " --pages . $page --" . | |
| 36 | + " fxo-red.pdf --overlay form-fields-and-annotations.pdf" . | |
| 37 | + " --repeat=1 -- a.pdf"}, | |
| 38 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 39 | + $td->NORMALIZE_NEWLINES); | |
| 40 | + $td->runtest("check output", | |
| 41 | + {$td->FILE => "a.pdf"}, | |
| 42 | + {$td->FILE => "overlay-copy-annotations-p$page.pdf"}); | |
| 43 | +} | |
| 44 | + | |
| 45 | +foreach my $d ([1, "appearances-1.pdf"], | |
| 46 | + [2, "appearances-1-rotated.pdf"]) | |
| 47 | +{ | |
| 48 | + my ($n, $file1) = @$d; | |
| 49 | + $td->runtest("copy/transfer with defaults", | |
| 50 | + {$td->COMMAND => "test_driver 80 $file1 minimal.pdf"}, | |
| 51 | + {$td->STRING => "test 80 done\n", $td->EXIT_STATUS => 0}, | |
| 52 | + $td->NORMALIZE_NEWLINES); | |
| 53 | + $td->runtest("check output A", | |
| 54 | + {$td->FILE => "a.pdf"}, | |
| 55 | + {$td->FILE => "test80a$n.pdf"}); | |
| 56 | + $td->runtest("check output B", | |
| 57 | + {$td->FILE => "b.pdf"}, | |
| 58 | + {$td->FILE => "test80b$n.pdf"}); | |
| 59 | +} | |
| 60 | + | |
| 61 | +$td->runtest("page extraction with fields", | |
| 62 | + {$td->COMMAND => | |
| 63 | + "qpdf --static-id --empty" . | |
| 64 | + " --pages fields-two-pages.pdf -- a.pdf"}, | |
| 65 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 66 | + $td->NORMALIZE_NEWLINES); | |
| 67 | +$td->runtest("check output", | |
| 68 | + {$td->FILE => "a.pdf"}, | |
| 69 | + {$td->FILE => "fields-pages-out.pdf"}); | |
| 70 | +$td->runtest("page splitting with fields", | |
| 71 | + {$td->COMMAND => | |
| 72 | + "qpdf --static-id" . | |
| 73 | + " --split-pages fields-two-pages.pdf split-out.pdf"}, | |
| 74 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 75 | + $td->NORMALIZE_NEWLINES); | |
| 76 | +for (my $i = 1; $i <= 2; ++$i) | |
| 77 | +{ | |
| 78 | + $td->runtest("check output", | |
| 79 | + {$td->FILE => "split-out-$i.pdf"}, | |
| 80 | + {$td->FILE => "fields-split-$i.pdf"}); | |
| 81 | +} | |
| 82 | +$td->runtest("keeping some fields", | |
| 83 | + {$td->COMMAND => | |
| 84 | + "qpdf --static-id fields-two-pages.pdf" . | |
| 85 | + " --pages . 1 minimal.pdf -- a.pdf"}, | |
| 86 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 87 | + $td->NORMALIZE_NEWLINES); | |
| 88 | +$td->runtest("check output", | |
| 89 | + {$td->FILE => "a.pdf"}, | |
| 90 | + {$td->FILE => "kept-some-fields.pdf"}); | |
| 91 | +$td->runtest("not keeping any fields", | |
| 92 | + {$td->COMMAND => | |
| 93 | + "qpdf --static-id kept-some-fields.pdf" . | |
| 94 | + " --pages . 2 -- a.pdf"}, | |
| 95 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 96 | + $td->NORMALIZE_NEWLINES); | |
| 97 | +$td->runtest("check output", | |
| 98 | + {$td->FILE => "a.pdf"}, | |
| 99 | + {$td->FILE => "kept-no-fields.pdf"}); | |
| 100 | +$td->runtest("other file first", | |
| 101 | + {$td->COMMAND => | |
| 102 | + "qpdf --qdf --no-original-object-ids" . | |
| 103 | + " --static-id fields-two-pages.pdf" . | |
| 104 | + " --pages ./fields-two-pages.pdf . 1 -- a.pdf"}, | |
| 105 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 106 | + $td->NORMALIZE_NEWLINES); | |
| 107 | +$td->runtest("check output", | |
| 108 | + {$td->FILE => "a.pdf"}, | |
| 109 | + {$td->FILE => "other-file-first.pdf"}); | |
| 110 | + | |
| 111 | +$td->runtest("field conflict resolution", | |
| 112 | + {$td->COMMAND => | |
| 113 | + "qpdf form-fields-and-annotations.pdf" . | |
| 114 | + " --pages . 1,1 ./form-fields-and-annotations.pdf 1,1 --" . | |
| 115 | + " --qdf --static-id --no-original-object-ids a.pdf"}, | |
| 116 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 117 | + $td->NORMALIZE_NEWLINES); | |
| 118 | +$td->runtest("check output", | |
| 119 | + {$td->FILE => "a.pdf"}, | |
| 120 | + {$td->FILE => "resolved-field-conflicts.pdf"}); | |
| 121 | + | |
| 122 | +# field-resource-conflict.pdf was crafted so that an appearance stream | |
| 123 | +# had an existing resource that it actually referenced in the | |
| 124 | +# appearance stream whose name, /F1_1, clashed with the result of | |
| 125 | +# resolving conflicts in /DR. It's a crazy corner case, but it if it | |
| 126 | +# ever happened, it would be really hard to track down, and it could | |
| 127 | +# arise through multiple passes through qpdf with intervening edits. | |
| 128 | +$td->runtest("appearance stream resource conflict", | |
| 129 | + {$td->COMMAND => | |
| 130 | + "qpdf field-resource-conflict.pdf" . | |
| 131 | + " --pages . 1,1 ./field-resource-conflict.pdf --" . | |
| 132 | + " --qdf --static-id --no-original-object-ids a.pdf"}, | |
| 133 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 134 | + $td->NORMALIZE_NEWLINES); | |
| 135 | +$td->runtest("check output", | |
| 136 | + {$td->FILE => "a.pdf"}, | |
| 137 | + {$td->FILE => "resolved-appearance-conflicts.pdf"}); | |
| 138 | + | |
| 139 | +$td->runtest("resource conflicts + flatten", | |
| 140 | + {$td->COMMAND => | |
| 141 | + "qpdf field-resource-conflict.pdf" . | |
| 142 | + " --pages . 1,1 ./field-resource-conflict.pdf --" . | |
| 143 | + " --generate-appearances --flatten-annotations=all" . | |
| 144 | + " --qdf --static-id --no-original-object-ids a.pdf"}, | |
| 145 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 146 | + $td->NORMALIZE_NEWLINES); | |
| 147 | +$td->runtest("check output", | |
| 148 | + {$td->FILE => "a.pdf"}, | |
| 149 | + {$td->FILE => "resolved-appearance-conflicts-generate.pdf"}); | |
| 150 | + | |
| 151 | +$td->runtest("default DA/Q", | |
| 152 | + {$td->COMMAND => | |
| 153 | + "qpdf form-fields-and-annotations.pdf" . | |
| 154 | + " --pages . default-da-q.pdf --" . | |
| 155 | + " --qdf --static-id --no-original-object-ids" . | |
| 156 | + " --generate-appearances a.pdf"}, | |
| 157 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 158 | + $td->NORMALIZE_NEWLINES); | |
| 159 | +$td->runtest("check output", | |
| 160 | + {$td->FILE => "a.pdf"}, | |
| 161 | + {$td->FILE => "default-da-q-out.pdf"}); | |
| 162 | + | |
| 163 | +$td->runtest("DA/appearance stream errors", | |
| 164 | + {$td->COMMAND => | |
| 165 | + "qpdf field-parse-errors.pdf" . | |
| 166 | + " --pages ./field-parse-errors.pdf --" . | |
| 167 | + " --qdf --static-id --no-original-object-ids a.pdf"}, | |
| 168 | + {$td->FILE => "field-parse-errors.out", $td->EXIT_STATUS => 3}, | |
| 169 | + $td->NORMALIZE_NEWLINES); | |
| 170 | +$td->runtest("check output", | |
| 171 | + {$td->FILE => "a.pdf"}, | |
| 172 | + {$td->FILE => "field-parse-errors-out.pdf"}); | |
| 173 | + | |
| 174 | +$td->runtest("Direct DR and annotations", | |
| 175 | + {$td->COMMAND => | |
| 176 | + "qpdf direct-dr.pdf --split-pages" . | |
| 177 | + " --qdf --static-id --no-original-object-ids" . | |
| 178 | + " split-out.pdf"}, | |
| 179 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 180 | + $td->NORMALIZE_NEWLINES); | |
| 181 | +$td->runtest("check output", | |
| 182 | + {$td->FILE => "split-out-1.pdf"}, | |
| 183 | + {$td->FILE => "direct-dr-out.pdf"}); | |
| 184 | + | |
| 185 | +cleanup(); | |
| 186 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/copy_foreign_objects.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('copy_foreign_objects'); | |
| 16 | + | |
| 17 | +my $n_tests = 11; | |
| 18 | + | |
| 19 | +foreach my $d ([25, 1], [26, 2], [27, 3]) | |
| 20 | +{ | |
| 21 | + my ($testn, $outn) = @$d; | |
| 22 | + $td->runtest("copy objects $outn", | |
| 23 | + {$td->COMMAND => "test_driver $testn" . | |
| 24 | + " minimal.pdf copy-foreign-objects-in.pdf"}, | |
| 25 | + {$td->FILE => "copy-foreign-objects-$testn.out", | |
| 26 | + $td->EXIT_STATUS => 0}, | |
| 27 | + $td->NORMALIZE_NEWLINES); | |
| 28 | + $td->runtest("check output", | |
| 29 | + {$td->FILE => "a.pdf"}, | |
| 30 | + {$td->FILE => "copy-foreign-objects-out$outn.pdf"}); | |
| 31 | +} | |
| 32 | +$td->runtest("copy objects error", | |
| 33 | + {$td->COMMAND => "test_driver 28" . | |
| 34 | + " copy-foreign-objects-in.pdf minimal.pdf"}, | |
| 35 | + {$td->FILE => "copy-foreign-objects-errors.out", | |
| 36 | + $td->EXIT_STATUS => 0}, | |
| 37 | + $td->NORMALIZE_NEWLINES); | |
| 38 | + | |
| 39 | +# Issue 449 involved indirect /Filter or /DecodeParms in streams that | |
| 40 | +# had their stream data replaced. The hand-generated | |
| 41 | +# indirect-filter.pdf file more or less reproduces the situation but | |
| 42 | +# doesn't result in the same internal error that 449 did with 10.0.1. | |
| 43 | +# The file issue-449.pdf was minimized by hand from a test case and | |
| 44 | +# does produce an internal error, though the exact reason is unclear. | |
| 45 | +# It seems to just have to do with the order in which things are | |
| 46 | +# copied. | |
| 47 | +$td->runtest("indirect filters", | |
| 48 | + {$td->COMMAND => "test_driver 69 indirect-filter.pdf"}, | |
| 49 | + {$td->STRING => "test 69 done\n", $td->EXIT_STATUS => 0}, | |
| 50 | + $td->NORMALIZE_NEWLINES); | |
| 51 | +foreach my $i (0, 1) | |
| 52 | +{ | |
| 53 | + $td->runtest("check output", | |
| 54 | + {$td->FILE => "auto-$i.pdf"}, | |
| 55 | + {$td->FILE => "indirect-filter-out-$i.pdf"}); | |
| 56 | +} | |
| 57 | +$td->runtest("issue 449", | |
| 58 | + {$td->COMMAND => "test_driver 69 issue-449.pdf"}, | |
| 59 | + {$td->STRING => "test 69 done\n", $td->EXIT_STATUS => 0}, | |
| 60 | + $td->NORMALIZE_NEWLINES); | |
| 61 | + | |
| 62 | +cleanup(); | |
| 63 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/custom_pipeline.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('custom_pipeline'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("output to custom pipeline", | |
| 20 | + {$td->COMMAND => "test_driver 33 minimal.pdf"}, | |
| 21 | + {$td->STRING => "test 33 done\n", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("check output", | |
| 24 | + {$td->FILE => "a.pdf"}, | |
| 25 | + {$td->FILE => "custom-pipeline.pdf"}); | |
| 26 | + | |
| 27 | +cleanup(); | |
| 28 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/dangling_refs.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('dangling_refs'); | |
| 16 | + | |
| 17 | +my @dangling = (qw(minimal dangling-refs)); | |
| 18 | +my $n_tests = 2 * scalar(@dangling); | |
| 19 | + | |
| 20 | +foreach my $f (@dangling) | |
| 21 | +{ | |
| 22 | + $td->runtest("dangling refs: $f", | |
| 23 | + {$td->COMMAND => "test_driver 53 $f.pdf"}, | |
| 24 | + {$td->FILE => "$f-dangling.out", $td->EXIT_STATUS => 0}, | |
| 25 | + $td->NORMALIZE_NEWLINES); | |
| 26 | + $td->runtest("check output", | |
| 27 | + {$td->FILE => "a.pdf"}, | |
| 28 | + {$td->FILE => "$f-dangling-out.pdf"}); | |
| 29 | +} | |
| 30 | +cleanup(); | |
| 31 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/decode_levels.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('decode_levels'); | |
| 16 | + | |
| 17 | +my $n_tests = 14; | |
| 18 | + | |
| 19 | +# image-streams.pdf is the output of examples/pdf-create. | |
| 20 | +# examples/pdf-create validates the actual image data. | |
| 21 | +# image-streams-small.pdf was manually created by editing | |
| 22 | +# pdf-create.cc to reduce width and height to 40x8 and ignoring | |
| 23 | +# errors. Its purpose was to get a small file with images with | |
| 24 | +# different filters for fuzz testing. | |
| 25 | +foreach my $l (qw(none generalized specialized all)) | |
| 26 | +{ | |
| 27 | + $td->runtest("image-streams: $l", | |
| 28 | + {$td->COMMAND => | |
| 29 | + "qpdf image-streams.pdf --compress-streams=n" . | |
| 30 | + " --decode-level=$l a.pdf"}, | |
| 31 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 32 | + $td->NORMALIZE_NEWLINES); | |
| 33 | + $td->runtest("check image-streams: $l", | |
| 34 | + {$td->COMMAND => "test_driver 39 a.pdf"}, | |
| 35 | + {$td->FILE => "image-streams-$l.out", $td->EXIT_STATUS => 0}, | |
| 36 | + $td->NORMALIZE_NEWLINES); | |
| 37 | +} | |
| 38 | + | |
| 39 | +# C API | |
| 40 | +$td->runtest("image-streams: C", | |
| 41 | + {$td->COMMAND => "qpdf-ctest 20 image-streams.pdf '' a.pdf"}, | |
| 42 | + {$td->STRING => "C test 20 done\n", $td->EXIT_STATUS => 0}, | |
| 43 | + $td->NORMALIZE_NEWLINES); | |
| 44 | +$td->runtest("check image-streams: C", | |
| 45 | + {$td->COMMAND => "test_driver 39 a.pdf"}, | |
| 46 | + {$td->FILE => "image-streams-specialized.out", | |
| 47 | + $td->EXIT_STATUS => 0}, | |
| 48 | + $td->NORMALIZE_NEWLINES); | |
| 49 | + | |
| 50 | +# Bad JPEG data | |
| 51 | +$td->runtest("check finds bad jpeg data", | |
| 52 | + {$td->COMMAND => "qpdf --check bad-jpeg.pdf"}, | |
| 53 | + {$td->FILE => "bad-jpeg-check.out", | |
| 54 | + $td->EXIT_STATUS => 3}, | |
| 55 | + $td->NORMALIZE_NEWLINES); | |
| 56 | +$td->runtest("precheck detects bad jpeg data", | |
| 57 | + {$td->COMMAND => "qpdf --static-id --decode-level=all" . | |
| 58 | + " bad-jpeg.pdf a.pdf"}, | |
| 59 | + {$td->FILE => "bad-jpeg.out", $td->EXIT_STATUS => 3}, | |
| 60 | + $td->NORMALIZE_NEWLINES); | |
| 61 | +$td->runtest("check file", | |
| 62 | + {$td->FILE => "a.pdf"}, | |
| 63 | + {$td->FILE => "bad-jpeg-out.pdf"}); | |
| 64 | +$td->runtest("get data", | |
| 65 | + {$td->COMMAND => "qpdf --show-object=6" . | |
| 66 | + " --filtered-stream-data bad-jpeg.pdf"}, | |
| 67 | + {$td->FILE => "bad-jpeg-show.out", $td->EXIT_STATUS => 3}, | |
| 68 | + $td->NORMALIZE_NEWLINES); | |
| 69 | + | |
| 70 | +cleanup(); | |
| 71 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/decode_parameters.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('decode_parameters'); | |
| 16 | + | |
| 17 | +my $n_tests = 6; | |
| 18 | + | |
| 19 | +# Make sure we ignore decode parameters that we don't understand | |
| 20 | +$td->runtest("unknown decode parameters", | |
| 21 | + {$td->COMMAND => "qpdf --check fax-decode-parms.pdf"}, | |
| 22 | + {$td->FILE => "fax-decode-parms.out", | |
| 23 | + $td->EXIT_STATUS => 0}, | |
| 24 | + $td->NORMALIZE_NEWLINES); | |
| 25 | + | |
| 26 | +$td->runtest("ignore broken decode parms with no filters", | |
| 27 | + {$td->COMMAND => "qpdf --check broken-decode-parms-no-filter.pdf"}, | |
| 28 | + {$td->FILE => "broken-decode-parms-no-filter.out", | |
| 29 | + $td->EXIT_STATUS => 0}, | |
| 30 | + $td->NORMALIZE_NEWLINES); | |
| 31 | + | |
| 32 | +$td->runtest("stream with indirect decode parms", | |
| 33 | + {$td->COMMAND => | |
| 34 | + "qpdf --static-id indirect-decode-parms.pdf a.pdf"}, | |
| 35 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 36 | +$td->runtest("check file", | |
| 37 | + {$td->FILE => "a.pdf"}, | |
| 38 | + {$td->FILE => "indirect-decode-parms-out.pdf"}); | |
| 39 | + | |
| 40 | +$td->runtest("decode parameters empty list", | |
| 41 | + {$td->COMMAND => "qpdf --static-id empty-decode-parms.pdf a.pdf"}, | |
| 42 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 43 | +$td->runtest("check file", | |
| 44 | + {$td->FILE => "a.pdf"}, | |
| 45 | + {$td->FILE => "empty-decode-parms-out.pdf"}); | |
| 46 | + | |
| 47 | +cleanup(); | |
| 48 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/deterministic_id.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('deterministic_id'); | |
| 16 | + | |
| 17 | +my $n_tests = 11; | |
| 18 | + | |
| 19 | +foreach my $d ('nn', 'ny', 'yn', 'yy') | |
| 20 | +{ | |
| 21 | + my $linearize = ($d =~ m/^y/); | |
| 22 | + my $ostream = ($d =~ m/y$/); | |
| 23 | + $td->runtest("deterministic ID: linearize/ostream=$d", | |
| 24 | + {$td->COMMAND => | |
| 25 | + "qpdf -deterministic-id" . | |
| 26 | + ($linearize ? " -linearize" : "") . | |
| 27 | + " -object-streams=" . ($ostream ? "generate" : "disable") . | |
| 28 | + " deterministic-id-in.pdf a.pdf"}, | |
| 29 | + {$td->STRING => "", | |
| 30 | + $td->EXIT_STATUS => 0}); | |
| 31 | + $td->runtest("compare files", | |
| 32 | + {$td->FILE => "a.pdf"}, | |
| 33 | + {$td->FILE => "deterministic-id-$d.pdf"}); | |
| 34 | +} | |
| 35 | + | |
| 36 | +$td->runtest("deterministic ID with encryption", | |
| 37 | + {$td->COMMAND => "qpdf -deterministic-id encrypted-with-images.pdf a.pdf"}, | |
| 38 | + {$td->STRING => "qpdf: INTERNAL ERROR: QPDFWriter::generateID" . | |
| 39 | + " has no data for deterministic ID." . | |
| 40 | + " This may happen if deterministic ID and" . | |
| 41 | + " file encryption are requested together.\n", | |
| 42 | + $td->EXIT_STATUS => 2}, | |
| 43 | + $td->NORMALIZE_NEWLINES); | |
| 44 | +$td->runtest("deterministic ID (C API)", | |
| 45 | + {$td->COMMAND => | |
| 46 | + "qpdf-ctest 19 deterministic-id-in.pdf '' a.pdf"}, | |
| 47 | + {$td->STRING => "C test 19 done\n", | |
| 48 | + $td->EXIT_STATUS => 0}, | |
| 49 | + $td->NORMALIZE_NEWLINES); | |
| 50 | +$td->runtest("compare files", | |
| 51 | + {$td->FILE => "a.pdf"}, | |
| 52 | + {$td->FILE => "deterministic-id-nn.pdf"}); | |
| 53 | + | |
| 54 | +cleanup(); | |
| 55 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/disable_filter_on_write.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('disable_filter_on_write'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("no filter on write", | |
| 20 | + {$td->COMMAND => "test_driver 70 filter-on-write.pdf"}, | |
| 21 | + {$td->STRING => "test 70 done\n", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("check output", | |
| 24 | + {$td->FILE => "a.pdf"}, | |
| 25 | + {$td->FILE => "filter-on-write-out.pdf"}); | |
| 26 | + | |
| 27 | +cleanup(); | |
| 28 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/encryption.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('encryption'); | |
| 16 | + | |
| 17 | +my $n_tests = 0; | |
| 18 | +# $n_tests incremented below | |
| 19 | + | |
| 20 | +# The enc-file.pdf files were encrypted using Acrobat 5.0, not the | |
| 21 | +# qpdf library. The files are decrypted using qpdf, then re-encrypted | |
| 22 | +# using qpdf with specific flags. The /P value is checked. The | |
| 23 | +# resulting files were saved and manually checked with Acrobat 5.0 to | |
| 24 | +# ensure that the security settings were as intended. | |
| 25 | + | |
| 26 | +# The enc-XI-file.pdf files were treated the same way but with Acrobat | |
| 27 | +# XI instead of Acrobat 5.0. They were used to create test files with | |
| 28 | +# newer encryption formats. | |
| 29 | + | |
| 30 | +# Values: basename, password, encryption flags, /P Encrypt key, | |
| 31 | +# extract-for-accessibility, extract-for-any-purpose, | |
| 32 | +# print-low-res, print-high-res, modify-assembly, modify-forms, | |
| 33 | +# modify-annotate, modify-other, modify-all | |
| 34 | +my @encrypted_files = | |
| 35 | + (['base', ''], # 1 | |
| 36 | + ['R3,V2', '', # 2 | |
| 37 | + '-accessibility=n -extract=n -print=full -modify=all', -532, | |
| 38 | + 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1], | |
| 39 | + ['R3,V2,U=view,O=view', 'view', # 3 | |
| 40 | + '-accessibility=y -extract=n -print=none -modify=none', -3392, | |
| 41 | + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], | |
| 42 | + ['R3,V2,O=master', 'master', # 4 | |
| 43 | + '-accessibility=n -extract=y -print=none -modify=annotate', -2576, | |
| 44 | + 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0], | |
| 45 | + ['R3,V2,O=master', '', # 5 | |
| 46 | + '-accessibility=n -extract=n -print=none -modify=form', -2624, | |
| 47 | + 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0], | |
| 48 | + ['R3,V2,U=view,O=master', 'view', # 6 | |
| 49 | + '-accessibility=n -extract=n -print=none -modify=assembly', -2880, | |
| 50 | + 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0], | |
| 51 | + ['R3,V2,U=view,O=master', 'master', # 7 | |
| 52 | + '-accessibility=n -print=low', -2564, | |
| 53 | + 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1], | |
| 54 | + ['R3,V2,U=view,O=master', 'master', # 8 | |
| 55 | + '-modify=all -assemble=n', -1028, | |
| 56 | + 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0], | |
| 57 | + ['R3,V2,U=view,O=master', 'master', # 9 | |
| 58 | + '-modify=none -form=y', -1068, | |
| 59 | + 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0], | |
| 60 | + ['R3,V2,U=view,O=master', 'master', # 10 | |
| 61 | + '-modify=annotate -assemble=n', -1036, | |
| 62 | + 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0], | |
| 63 | + ['R3,V2,U=view,O=master', 'master', # 11 | |
| 64 | + '-form=n', -260, | |
| 65 | + 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0], | |
| 66 | + ['R3,V2,U=view,O=master', 'master', # 12 | |
| 67 | + '-annotate=n', -36, | |
| 68 | + 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0], | |
| 69 | + ['R3,V2,U=view,O=master', 'master', # 13 | |
| 70 | + '-modify-other=n', -12, | |
| 71 | + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], | |
| 72 | + ['R2,V1', '', # 14 | |
| 73 | + '-print=n -modify=n -extract=n -annotate=n', -64, | |
| 74 | + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
| 75 | + ['R2,V1,U=view,O=view', 'view', # 15 | |
| 76 | + '-print=y -modify=n -extract=n -annotate=n', -60, | |
| 77 | + 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0], | |
| 78 | + ['R2,V1,O=master', 'master', # 16 | |
| 79 | + '-print=n -modify=y -extract=n -annotate=n', -56, | |
| 80 | + 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0], | |
| 81 | + ['R2,V1,O=master', '', # 17 | |
| 82 | + '-print=n -modify=n -extract=y -annotate=n', -48, | |
| 83 | + 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], | |
| 84 | + ['R2,V1,U=view,O=master', 'view', # 18 | |
| 85 | + '-print=n -modify=n -extract=n -annotate=y', -32, | |
| 86 | + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], | |
| 87 | + ['R2,V1,U=view,O=master', 'master', # 19 | |
| 88 | + '', -4, | |
| 89 | + 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], | |
| 90 | + ['long-password', 'asdf asdf asdf asdf asdf asdf qwer'], # 20 | |
| 91 | + ['long-password', 'asdf asdf asdf asdf asdf asdf qw'], # 21 | |
| 92 | + ['XI-base', ''], # 22 | |
| 93 | + ['XI-R6,V5,O=master', '', # 23 | |
| 94 | + '-extract=n -print=none -modify=assembly', -2368, | |
| 95 | + 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], | |
| 96 | + ['XI-R6,V5,O=master', 'master', # 24 | |
| 97 | + '-extract=n -print=none -modify=assembly', -2368, | |
| 98 | + 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], | |
| 99 | + ['XI-R6,V5,U=view,O=master', 'view', # 25 | |
| 100 | + '-print=low', -2052, | |
| 101 | + 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1], | |
| 102 | + ['XI-R6,V5,U=view,O=master', 'master', # 26 | |
| 103 | + '-print=low', -2052, | |
| 104 | + 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1], | |
| 105 | + ['XI-R6,V5,U=view,O=master', 'master', # 27 | |
| 106 | + '-accessibility=n', -4, # -accessibility=n has no effect | |
| 107 | + 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], | |
| 108 | + ['XI-long-password', 'qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm'], # 28; -accessibility=n has no effect | |
| 109 | + ['XI-long-password', 'qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcv'], # 29 | |
| 110 | + ['XI-R6,V5,U=wwwww,O=wwwww', 'wwwww', # 30 | |
| 111 | + '', -4, | |
| 112 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], | |
| 113 | + ); | |
| 114 | + | |
| 115 | +$n_tests += 8 + (2 * (@encrypted_files)) + (7 * (@encrypted_files - 6)) + 9; | |
| 116 | + | |
| 117 | +$td->runtest("encrypted file", | |
| 118 | + {$td->COMMAND => "test_driver 2 encrypted-with-images.pdf"}, | |
| 119 | + {$td->FILE => "encrypted1.out", | |
| 120 | + $td->EXIT_STATUS => 0}, | |
| 121 | + $td->NORMALIZE_NEWLINES); | |
| 122 | +$td->runtest("preserve encryption", | |
| 123 | + {$td->COMMAND => "qpdf encrypted-with-images.pdf encrypted-with-images.enc"}, | |
| 124 | + {$td->STRING => "", | |
| 125 | + $td->EXIT_STATUS => 0}); | |
| 126 | +$td->runtest("recheck encrypted file", | |
| 127 | + {$td->COMMAND => "test_driver 2 encrypted-with-images.enc"}, | |
| 128 | + {$td->FILE => "encrypted1.out", | |
| 129 | + $td->EXIT_STATUS => 0}, | |
| 130 | + $td->NORMALIZE_NEWLINES); | |
| 131 | + | |
| 132 | +$td->runtest("empty owner password", | |
| 133 | + {$td->COMMAND => "qpdf --encrypt u '' 256 -- minimal.pdf a.pdf"}, | |
| 134 | + {$td->REGEXP => ".*is insecure.*--allow-insecure.*", | |
| 135 | + $td->EXIT_STATUS => 2}, | |
| 136 | + $td->NORMALIZE_NEWLINES); | |
| 137 | +$td->runtest("allow insecure", | |
| 138 | + {$td->COMMAND => "qpdf --encrypt u '' 256 --allow-insecure --" . | |
| 139 | + " minimal.pdf a.pdf"}, | |
| 140 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 141 | + $td->NORMALIZE_NEWLINES); | |
| 142 | +$td->runtest("check insecure", | |
| 143 | + {$td->COMMAND => "qpdf --check a.pdf"}, | |
| 144 | + {$td->FILE => "insecure-passwords.out", $td->EXIT_STATUS => 0}, | |
| 145 | + $td->NORMALIZE_NEWLINES); | |
| 146 | + | |
| 147 | +# Test that long passwords that are one character too short fail. We | |
| 148 | +# test the truncation cases in the loop below by using passwords | |
| 149 | +# longer than the supported length. | |
| 150 | +$td->runtest("significant password characters (V < 5)", | |
| 151 | + {$td->COMMAND => "qpdf --check enc-long-password.pdf" . | |
| 152 | + " --password='asdf asdf asdf asdf asdf asdf q'"}, | |
| 153 | + {$td->REGEXP => ".*invalid password.*", $td->EXIT_STATUS => 2}); | |
| 154 | +$td->runtest("significant password characters (V = 5)", | |
| 155 | + {$td->COMMAND => "qpdf --check enc-XI-long-password.pdf" . | |
| 156 | + " --password=qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxc"}, | |
| 157 | + {$td->REGEXP => ".*invalid password.*", $td->EXIT_STATUS => 2}); | |
| 158 | + | |
| 159 | +my $enc_base = undef; | |
| 160 | +my $enc_n = 0; | |
| 161 | +foreach my $d (@encrypted_files) | |
| 162 | +{ | |
| 163 | + ++$enc_n; | |
| 164 | + my ($file, $pass, $xeflags, $P, $match_owner, $match_user, | |
| 165 | + $accessible, $extract, $printlow, $printhigh, | |
| 166 | + $modifyassembly, $modifyform, $modifyannot, | |
| 167 | + $modifyother, $modifyall) = @$d; | |
| 168 | + | |
| 169 | + my $f = sub { $_[0] ? "allowed" : "not allowed" }; | |
| 170 | + my $jf = sub { $_[0] ? "true" : "false" }; | |
| 171 | + my $enc_details = ""; | |
| 172 | + my $enc_json = | |
| 173 | + "{\n" . | |
| 174 | + " \"version\": 2,\n" . | |
| 175 | + " \"parameters\": {\n" . | |
| 176 | + " \"decodelevel\": \"generalized\"\n" . | |
| 177 | + " },\n" . | |
| 178 | + " \"encrypt\": {\n" . | |
| 179 | + " \"capabilities\": {\n"; | |
| 180 | + if ($match_owner) | |
| 181 | + { | |
| 182 | + $enc_details .= "Supplied password is owner password\n"; | |
| 183 | + } | |
| 184 | + if ($match_user) | |
| 185 | + { | |
| 186 | + $enc_details .= "Supplied password is user password\n"; | |
| 187 | + } | |
| 188 | + $enc_details .= | |
| 189 | + "extract for accessibility: " . &$f($accessible) . "\n" . | |
| 190 | + "extract for any purpose: " . &$f($extract) . "\n" . | |
| 191 | + "print low resolution: " . &$f($printlow) . "\n" . | |
| 192 | + "print high resolution: " . &$f($printhigh) . "\n" . | |
| 193 | + "modify document assembly: " . &$f($modifyassembly) . "\n" . | |
| 194 | + "modify forms: " . &$f($modifyform) . "\n" . | |
| 195 | + "modify annotations: " . &$f($modifyannot) . "\n" . | |
| 196 | + "modify other: " . &$f($modifyother) . "\n" . | |
| 197 | + "modify anything: " . &$f($modifyall) . "\n"; | |
| 198 | + $enc_json .= | |
| 199 | + " \"accessibility\": " . &$jf($accessible) . ",\n" . | |
| 200 | + " \"extract\": " . &$jf($extract) . ",\n" . | |
| 201 | + " \"modify\": " . &$jf($modifyall) . ",\n" . | |
| 202 | + " \"modifyannotations\": " . &$jf($modifyannot) . ",\n" . | |
| 203 | + " \"modifyassembly\": " . &$jf($modifyassembly) . ",\n" . | |
| 204 | + " \"modifyforms\": " . &$jf($modifyform) . ",\n" . | |
| 205 | + " \"modifyother\": " . &$jf($modifyother) . ",\n" . | |
| 206 | + " \"printhigh\": " . &$jf($printhigh) . ",\n" . | |
| 207 | + " \"printlow\": " . &$jf($printlow) . "\n" . | |
| 208 | + " },\n" . | |
| 209 | + " \"encrypted\": true,\n" . | |
| 210 | + " \"ownerpasswordmatched\": ---opm---,\n" . | |
| 211 | + " \"parameters\": {\n" . | |
| 212 | + " \"P\": ---P---,\n" . | |
| 213 | + " \"R\": ---R---,\n" . | |
| 214 | + " \"V\": ---V---,\n" . | |
| 215 | + " \"bits\": ---bits---,\n" . | |
| 216 | + " \"filemethod\": \"---method---\",\n" . | |
| 217 | + " \"key\": null,\n" . | |
| 218 | + " \"method\": \"---method---\",\n" . | |
| 219 | + " \"streammethod\": \"---method---\",\n" . | |
| 220 | + " \"stringmethod\": \"---method---\"\n" . | |
| 221 | + " },\n" . | |
| 222 | + " \"userpasswordmatched\": ---upm---\n" . | |
| 223 | + " }\n" . | |
| 224 | + "}\n"; | |
| 225 | + if ($file =~ m/XI-/) | |
| 226 | + { | |
| 227 | + $enc_details .= | |
| 228 | + "stream encryption method: AESv3\n" . | |
| 229 | + "string encryption method: AESv3\n" . | |
| 230 | + "file encryption method: AESv3\n"; | |
| 231 | + } | |
| 232 | + | |
| 233 | + # Test writing to stdout | |
| 234 | + $td->runtest("decrypt $file", | |
| 235 | + {$td->COMMAND => | |
| 236 | + "qpdf --static-id -qdf --object-streams=disable" . | |
| 237 | + " --no-original-object-ids" . | |
| 238 | + " --password=\"$pass\" enc-$file.pdf -" . | |
| 239 | + " > $file.enc"}, | |
| 240 | + {$td->STRING => "", | |
| 241 | + $td->EXIT_STATUS => 0}); | |
| 242 | + if ($file =~ m/base$/) | |
| 243 | + { | |
| 244 | + $enc_base = $file; | |
| 245 | + $td->runtest("check ID", | |
| 246 | + {$td->COMMAND => "perl check-ID.pl $file.enc"}, | |
| 247 | + {$td->STRING => "ID okay\n", | |
| 248 | + $td->EXIT_STATUS => 0}, | |
| 249 | + $td->NORMALIZE_NEWLINES); | |
| 250 | + } | |
| 251 | + else | |
| 252 | + { | |
| 253 | + $td->runtest("check against base", | |
| 254 | + {$td->COMMAND => | |
| 255 | + "sh ./diff-encrypted $enc_base.enc $file.enc"}, | |
| 256 | + {$td->STRING => "okay\n", | |
| 257 | + $td->EXIT_STATUS => 0}, | |
| 258 | + $td->NORMALIZE_NEWLINES); | |
| 259 | + } | |
| 260 | + if ($file =~ m/^(?:XI-)?R(\d),V(\d)(?:,U=(\w+))?(?:,O=(\w+))?$/) | |
| 261 | + { | |
| 262 | + my $R = $1; | |
| 263 | + my $V = $2; | |
| 264 | + my $upass = $3 || ""; | |
| 265 | + my $opass = $4 || ""; | |
| 266 | + my $bits = (($V == 5) ? 256 : ($V == 2) ? 128 : 40); | |
| 267 | + my $method = $bits == 256 ? "AESv3" : "RC4"; | |
| 268 | + my $opm = ($pass eq $opass ? "true" : "false"); | |
| 269 | + my $upm = ($pass eq $upass ? "true" : "false"); | |
| 270 | + $enc_json =~ s/---R---/$R/; | |
| 271 | + $enc_json =~ s/---P---/$P/; | |
| 272 | + $enc_json =~ s/---V---/$V/; | |
| 273 | + $enc_json =~ s/---bits---/$bits/; | |
| 274 | + $enc_json =~ s/---method---/$method/g; | |
| 275 | + $enc_json =~ s/---opm---/$opm/; | |
| 276 | + $enc_json =~ s/---upm---/$upm/; | |
| 277 | + | |
| 278 | + my $eflags = "--allow-weak-crypto" . | |
| 279 | + " -encrypt \"$upass\" \"$opass\" $bits $xeflags --"; | |
| 280 | + if (($opass eq "") && ($bits == 256)) | |
| 281 | + { | |
| 282 | + $eflags =~ s/--$/--allow-insecure --/; | |
| 283 | + } | |
| 284 | + if (($pass ne $upass) && ($V >= 5)) | |
| 285 | + { | |
| 286 | + # V >= 5 can no longer recover user password with owner | |
| 287 | + # password. | |
| 288 | + $upass = ""; | |
| 289 | + } | |
| 290 | + my $accessibility_warning = ""; | |
| 291 | + if (($R > 3) && ($eflags =~ /accessibility=n/)) | |
| 292 | + { | |
| 293 | + $accessibility_warning = | |
| 294 | + "qpdf: -accessibility=n is ignored" . | |
| 295 | + " for modern encryption formats\n"; | |
| 296 | + } | |
| 297 | + $td->runtest("encrypt $file", | |
| 298 | + {$td->COMMAND => | |
| 299 | + "qpdf --static-id --no-original-object-ids -qdf" . | |
| 300 | + " $eflags $file.enc $file.enc2"}, | |
| 301 | + {$td->STRING => $accessibility_warning, | |
| 302 | + $td->EXIT_STATUS => 0}, | |
| 303 | + $td->NORMALIZE_NEWLINES); | |
| 304 | + $td->runtest("check /P enc2 ($enc_n)", | |
| 305 | + {$td->COMMAND => | |
| 306 | + "qpdf --show-encryption --password=\"$pass\"" . | |
| 307 | + " $file.enc2"}, | |
| 308 | + {$td->STRING => "R = $R\nP = $P\n" . | |
| 309 | + "User password = $upass\n$enc_details", | |
| 310 | + $td->EXIT_STATUS => 0}, | |
| 311 | + $td->NORMALIZE_NEWLINES); | |
| 312 | + $td->runtest("json encrypt key ($enc_n)", | |
| 313 | + {$td->COMMAND => | |
| 314 | + "qpdf --json --json-key=encrypt" . | |
| 315 | + " --password=\"$pass\"" . | |
| 316 | + " $file.enc2"}, | |
| 317 | + {$td->STRING => $enc_json, $td->EXIT_STATUS => 0}, | |
| 318 | + $td->NORMALIZE_NEWLINES); | |
| 319 | + $td->runtest("decrypt again", | |
| 320 | + {$td->COMMAND => | |
| 321 | + "qpdf --static-id --no-original-object-ids -qdf" . | |
| 322 | + " --password=\"$pass\"" . | |
| 323 | + " $file.enc2 $file.enc3"}, | |
| 324 | + {$td->STRING => "", | |
| 325 | + $td->EXIT_STATUS => 0}); | |
| 326 | + $td->runtest("compare", | |
| 327 | + {$td->FILE => "$file.enc"}, | |
| 328 | + {$td->FILE => "$file.enc3"}); | |
| 329 | + $td->runtest("preserve encryption", | |
| 330 | + {$td->COMMAND => | |
| 331 | + "qpdf --static-id --password=\"$pass\"" . | |
| 332 | + " $file.enc2 $file.enc4"}, | |
| 333 | + {$td->STRING => "", | |
| 334 | + $td->EXIT_STATUS => 0}); | |
| 335 | + $td->runtest("check /P enc4 ($enc_n)", | |
| 336 | + {$td->COMMAND => | |
| 337 | + "qpdf --show-encryption --password=\"$pass\"" . | |
| 338 | + " $file.enc4"}, | |
| 339 | + {$td->STRING => "R = $R\nP = $P\n" . | |
| 340 | + "User password = $upass\n$enc_details", | |
| 341 | + $td->EXIT_STATUS => 0}, | |
| 342 | + $td->NORMALIZE_NEWLINES); | |
| 343 | + } | |
| 344 | +} | |
| 345 | + | |
| 346 | +$td->runtest("non-encrypted", | |
| 347 | + {$td->COMMAND => "qpdf --show-encryption enc-base.pdf"}, | |
| 348 | + {$td->STRING => "File is not encrypted\n", | |
| 349 | + $td->EXIT_STATUS => 0}, | |
| 350 | + $td->NORMALIZE_NEWLINES); | |
| 351 | + | |
| 352 | +$td->runtest("invalid password", | |
| 353 | + {$td->COMMAND => "qpdf -qdf --password=quack" . | |
| 354 | + " enc-R2,V1,U=view,O=view.pdf a.qdf"}, | |
| 355 | + {$td->STRING => | |
| 356 | + "qpdf: enc-R2,V1,U=view,O=view.pdf: invalid password\n", | |
| 357 | + $td->EXIT_STATUS => 2}, | |
| 358 | + $td->NORMALIZE_NEWLINES); | |
| 359 | +$td->runtest("C API: invalid password", | |
| 360 | + {$td->COMMAND => | |
| 361 | + "qpdf-ctest 2 enc-R2,V1,U=view,O=view.pdf '' a.qdf"}, | |
| 362 | + {$td->FILE => "c-invalid-password.out", $td->EXIT_STATUS => 0}, | |
| 363 | + $td->NORMALIZE_NEWLINES); | |
| 364 | + | |
| 365 | +my @cenc = ( | |
| 366 | + [11, 'hybrid-xref.pdf', "''", 'r2', "", ""], | |
| 367 | + [12, 'hybrid-xref.pdf', "''", 'r3', "", ""], | |
| 368 | + [15, 'hybrid-xref.pdf', "''", 'r4', "", ""], | |
| 369 | + [17, 'hybrid-xref.pdf', "''", 'r5', "", "owner3"], | |
| 370 | + [18, 'hybrid-xref.pdf', "''", 'r6', "", "user4"], | |
| 371 | + [13, 'c-r2.pdf', 'user1', 'decrypt with user', | |
| 372 | + "user password: user1\n", ""], | |
| 373 | + [13, 'c-r3.pdf', 'owner2', 'decrypt with owner', | |
| 374 | + "user password: user2\n", ""], | |
| 375 | + [13, 'c-r5-in.pdf', 'user3', 'decrypt R5 with user', | |
| 376 | + "user password: user3\n", ""], | |
| 377 | + [13, 'c-r6-in.pdf', 'owner4', 'decrypt R6 with owner', | |
| 378 | + "user password: \n", ""], | |
| 379 | + ); | |
| 380 | +$n_tests += 2 * @cenc; | |
| 381 | + | |
| 382 | +foreach my $d (@cenc) | |
| 383 | +{ | |
| 384 | + my ($n, $infile, $pass, $description, $output, $checkpass) = @$d; | |
| 385 | + my $outfile = $description; | |
| 386 | + $outfile =~ s/ /-/g; | |
| 387 | + my $pdf_outfile = "c-$outfile.pdf"; | |
| 388 | + my $check_outfile = "c-$outfile.out"; | |
| 389 | + $td->runtest("C API encryption: $description", | |
| 390 | + {$td->COMMAND => "qpdf-ctest $n $infile $pass a.pdf"}, | |
| 391 | + {$td->STRING => $output . "C test $n done\n", | |
| 392 | + $td->EXIT_STATUS => 0}, | |
| 393 | + $td->NORMALIZE_NEWLINES); | |
| 394 | + if (-f $pdf_outfile) | |
| 395 | + { | |
| 396 | + $td->runtest("check $description content", | |
| 397 | + {$td->FILE => "a.pdf"}, | |
| 398 | + {$td->FILE => $pdf_outfile}); | |
| 399 | + } | |
| 400 | + else | |
| 401 | + { | |
| 402 | + # QPDF doesn't provide any way to make the random bits in | |
| 403 | + # /Perms static, so we have no way to predictably create a | |
| 404 | + # /V=5 encrypted file. It's not worth adding this...the test | |
| 405 | + # suite is adequate without having a statically predictable | |
| 406 | + # file. | |
| 407 | + $td->runtest("check $description", | |
| 408 | + {$td->COMMAND => | |
| 409 | + "qpdf --check a.pdf --password=$checkpass"}, | |
| 410 | + {$td->FILE => $check_outfile, $td->EXIT_STATUS => 0}, | |
| 411 | + $td->NORMALIZE_NEWLINES); | |
| 412 | + } | |
| 413 | +} | |
| 414 | + | |
| 415 | +# Test combinations of linearization and encryption. Note that we do | |
| 416 | +# content checks on encrypted and linearized files in various | |
| 417 | +# combinations below. Here we are just making sure that they are | |
| 418 | +# linearized and/or encrypted as desired. | |
| 419 | + | |
| 420 | +$td->runtest("linearize encrypted file", | |
| 421 | + {$td->COMMAND => "qpdf --linearize encrypted-with-images.pdf a.pdf"}, | |
| 422 | + {$td->STRING => "", | |
| 423 | + $td->EXIT_STATUS => 0}); | |
| 424 | +$td->runtest("check encryption", | |
| 425 | + {$td->COMMAND => "qpdf --show-encryption a.pdf", | |
| 426 | + $td->FILTER => "grep -v allowed | grep -v Supplied"}, | |
| 427 | + {$td->STRING => "R = 3\nP = -4\nUser password = \n", | |
| 428 | + $td->EXIT_STATUS => 0}, | |
| 429 | + $td->NORMALIZE_NEWLINES); | |
| 430 | +$td->runtest("check linearization", | |
| 431 | + {$td->COMMAND => "qpdf --check-linearization a.pdf"}, | |
| 432 | + {$td->STRING => "a.pdf: no linearization errors\n", | |
| 433 | + $td->EXIT_STATUS => 0}, | |
| 434 | + $td->NORMALIZE_NEWLINES); | |
| 435 | +$td->runtest("linearize and encrypt file", | |
| 436 | + {$td->COMMAND => | |
| 437 | + "qpdf --linearize --encrypt user owner 128 --use-aes=y --" . | |
| 438 | + " lin-special.pdf a.pdf"}, | |
| 439 | + {$td->STRING => "", | |
| 440 | + $td->EXIT_STATUS => 0}); | |
| 441 | +$td->runtest("check encryption", | |
| 442 | + {$td->COMMAND => "qpdf --show-encryption --password=owner a.pdf", | |
| 443 | + $td->FILTER => "grep -v allowed | grep -v method | grep -v Supplied"}, | |
| 444 | + {$td->STRING => "R = 4\nP = -4\nUser password = user\n", | |
| 445 | + $td->EXIT_STATUS => 0}, | |
| 446 | + $td->NORMALIZE_NEWLINES); | |
| 447 | +$td->runtest("check linearization", | |
| 448 | + {$td->COMMAND => "qpdf --check-linearization" . | |
| 449 | + " --password=user a.pdf"}, | |
| 450 | + {$td->STRING => "a.pdf: no linearization errors\n", | |
| 451 | + $td->EXIT_STATUS => 0}, | |
| 452 | + $td->NORMALIZE_NEWLINES); | |
| 453 | + | |
| 454 | +# Test --check-linearization of non-linearized file | |
| 455 | +$n_tests += 1; | |
| 456 | +$td->runtest("check linearization of non-linearized file", | |
| 457 | + {$td->COMMAND => "qpdf --check-linearization minimal.pdf"}, | |
| 458 | + {$td->STRING => "minimal.pdf is not linearized\n", | |
| 459 | + $td->EXIT_STATUS => 0}, | |
| 460 | + $td->NORMALIZE_NEWLINES); | |
| 461 | + | |
| 462 | + | |
| 463 | +# Test AES encryption in various ways. | |
| 464 | +$n_tests += 18; | |
| 465 | +$td->runtest("encrypt with AES", | |
| 466 | + {$td->COMMAND => "qpdf --encrypt '' o 128 --use-aes=y --" . | |
| 467 | + " enc-base.pdf a.pdf"}, | |
| 468 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 469 | +$td->runtest("check encryption", | |
| 470 | + {$td->COMMAND => "qpdf --show-encryption a.pdf", | |
| 471 | + $td->FILTER => "grep -v allowed | grep -v method | grep -v Supplied"}, | |
| 472 | + {$td->STRING => "R = 4\nP = -4\nUser password = \n", | |
| 473 | + $td->EXIT_STATUS => 0}, | |
| 474 | + $td->NORMALIZE_NEWLINES); | |
| 475 | +$td->runtest("convert original to qdf", | |
| 476 | + {$td->COMMAND => "qpdf --static-id --no-original-object-ids" . | |
| 477 | + " --qdf --min-version=1.6 enc-base.pdf a.qdf"}, | |
| 478 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 479 | +$td->runtest("convert encrypted to qdf", | |
| 480 | + {$td->COMMAND => "qpdf --static-id --no-original-object-ids" . | |
| 481 | + " --qdf a.pdf b.qdf"}, | |
| 482 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 483 | +$td->runtest("compare files", | |
| 484 | + {$td->FILE => 'a.qdf'}, | |
| 485 | + {$td->FILE => 'b.qdf'}); | |
| 486 | +$td->runtest("linearize with AES and object streams", | |
| 487 | + {$td->COMMAND => "qpdf --encrypt '' o 128 --use-aes=y --" . | |
| 488 | + " --linearize --object-streams=generate enc-base.pdf a.pdf"}, | |
| 489 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 490 | +$td->runtest("check encryption", | |
| 491 | + {$td->COMMAND => "qpdf --show-encryption a.pdf", | |
| 492 | + $td->FILTER => "grep -v allowed | grep -v method | grep -v Supplied"}, | |
| 493 | + {$td->STRING => "R = 4\nP = -4\nUser password = \n", | |
| 494 | + $td->EXIT_STATUS => 0}, | |
| 495 | + $td->NORMALIZE_NEWLINES); | |
| 496 | +$td->runtest("linearize original", | |
| 497 | + {$td->COMMAND => "qpdf --linearize --object-streams=generate" . | |
| 498 | + " enc-base.pdf b.pdf"}, | |
| 499 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 500 | +$td->runtest("convert linearized original to qdf", | |
| 501 | + {$td->COMMAND => "qpdf --static-id --no-original-object-ids" . | |
| 502 | + " --qdf --object-streams=generate --min-version=1.6" . | |
| 503 | + " b.pdf a.qdf"}, | |
| 504 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 505 | +$td->runtest("convert encrypted to qdf", | |
| 506 | + {$td->COMMAND => "qpdf --static-id --no-original-object-ids" . | |
| 507 | + " --qdf --object-streams=generate a.pdf b.qdf"}, | |
| 508 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 509 | +$td->runtest("compare files", | |
| 510 | + {$td->FILE => 'a.qdf'}, | |
| 511 | + {$td->FILE => 'b.qdf'}); | |
| 512 | +$td->runtest("force version on aes encrypted", | |
| 513 | + {$td->COMMAND => "qpdf --force-version=1.4 a.pdf b.pdf"}, | |
| 514 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 515 | +$td->runtest("check", | |
| 516 | + {$td->COMMAND => "qpdf --check b.pdf"}, | |
| 517 | + {$td->FILE => "aes-forced-check.out", | |
| 518 | + $td->EXIT_STATUS => 0}, | |
| 519 | + $td->NORMALIZE_NEWLINES); | |
| 520 | +$td->runtest("make sure there is no xref stream", | |
| 521 | + {$td->COMMAND => "grep /ObjStm b.pdf | wc -l"}, | |
| 522 | + {$td->REGEXP => "\\s*0\\s*", $td->EXIT_STATUS => 0}, | |
| 523 | + $td->NORMALIZE_NEWLINES); | |
| 524 | +$td->runtest("encrypt with V=5,R=5", | |
| 525 | + {$td->COMMAND => | |
| 526 | + "qpdf --encrypt user owner 256 --force-R5 -- " . | |
| 527 | + "minimal.pdf a.pdf"}, | |
| 528 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 529 | +$td->runtest("check encryption", | |
| 530 | + {$td->COMMAND => "qpdf --check a.pdf --password=owner"}, | |
| 531 | + {$td->FILE => "V5R5.out", $td->EXIT_STATUS => 0}, | |
| 532 | + $td->NORMALIZE_NEWLINES); | |
| 533 | +$td->runtest("encrypt with V=5,R=6", | |
| 534 | + {$td->COMMAND => | |
| 535 | + "qpdf --encrypt user owner 256 -- " . | |
| 536 | + "minimal.pdf a.pdf"}, | |
| 537 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 538 | +$td->runtest("check encryption", | |
| 539 | + {$td->COMMAND => "qpdf --check a.pdf --password=user"}, | |
| 540 | + {$td->FILE => "V5R6.out", $td->EXIT_STATUS => 0}, | |
| 541 | + $td->NORMALIZE_NEWLINES); | |
| 542 | + | |
| 543 | +# Look at some actual V4 files | |
| 544 | +$n_tests += 17; | |
| 545 | +foreach my $d (['--force-V4', 'V4'], | |
| 546 | + ['--cleartext-metadata', 'V4-clearmeta'], | |
| 547 | + ['--use-aes=y', 'V4-aes'], | |
| 548 | + ['--cleartext-metadata --use-aes=y', 'V4-aes-clearmeta']) | |
| 549 | +{ | |
| 550 | + my ($args, $out) = @$d; | |
| 551 | + $td->runtest("encrypt $args", | |
| 552 | + {$td->COMMAND => "qpdf --static-aes-iv --static-id" . | |
| 553 | + " --allow-weak-crypto --encrypt '' '' 128 $args --" . | |
| 554 | + " enc-base.pdf a.pdf"}, | |
| 555 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 556 | + $td->runtest("check output", | |
| 557 | + {$td->FILE => "a.pdf"}, | |
| 558 | + {$td->FILE => "$out.pdf"}); | |
| 559 | + $td->runtest("show encryption", | |
| 560 | + {$td->COMMAND => "qpdf --show-encryption a.pdf"}, | |
| 561 | + {$td->FILE => "$out-encryption.out", $td->EXIT_STATUS => 0}, | |
| 562 | + $td->NORMALIZE_NEWLINES); | |
| 563 | +} | |
| 564 | +# Crypt Filter | |
| 565 | +$td->runtest("decrypt with crypt filter", | |
| 566 | + {$td->COMMAND => "qpdf --decrypt --static-id" . | |
| 567 | + " metadata-crypt-filter.pdf a.pdf"}, | |
| 568 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 569 | +$td->runtest("check output", | |
| 570 | + {$td->FILE => 'a.pdf'}, | |
| 571 | + {$td->FILE => 'decrypted-crypt-filter.pdf'}); | |
| 572 | +$td->runtest("nontrivial crypt filter", | |
| 573 | + {$td->COMMAND => "qpdf --qdf --decrypt --static-id" . | |
| 574 | + " nontrivial-crypt-filter.pdf --password=asdfqwer a.pdf"}, | |
| 575 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 576 | +$td->runtest("check output", | |
| 577 | + {$td->FILE => 'a.pdf'}, | |
| 578 | + {$td->FILE => 'nontrivial-crypt-filter-decrypted.pdf'}); | |
| 579 | +$td->runtest("show nontrivial EFF", | |
| 580 | + {$td->COMMAND => "qpdf --show-encryption" . | |
| 581 | + " nontrivial-crypt-filter.pdf --password=asdfqwer"}, | |
| 582 | + {$td->FILE => "nontrivial-crypt-filter.out", | |
| 583 | + $td->EXIT_STATUS => 0}, | |
| 584 | + $td->NORMALIZE_NEWLINES); | |
| 585 | + | |
| 586 | +# Copy encryption parameters | |
| 587 | +$n_tests += 10; | |
| 588 | +$td->runtest("create reference qdf", | |
| 589 | + {$td->COMMAND => | |
| 590 | + "qpdf --qdf --no-original-object-ids minimal.pdf a.qdf"}, | |
| 591 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 592 | +$td->runtest("create encrypted file", | |
| 593 | + {$td->COMMAND => | |
| 594 | + "qpdf --encrypt user owner 128 --use-aes=y --extract=n --" . | |
| 595 | + " minimal.pdf a.pdf"}, | |
| 596 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 597 | +$td->runtest("copy encryption parameters", | |
| 598 | + {$td->COMMAND => "test_driver 30 minimal.pdf a.pdf"}, | |
| 599 | + {$td->STRING => "test 30 done\n", $td->EXIT_STATUS => 0}, | |
| 600 | + $td->NORMALIZE_NEWLINES); | |
| 601 | +$td->runtest("check output encryption", | |
| 602 | + {$td->COMMAND => "qpdf --show-encryption b.pdf --password=owner"}, | |
| 603 | + {$td->FILE => "copied-encryption.out", | |
| 604 | + $td->EXIT_STATUS => 0}, | |
| 605 | + $td->NORMALIZE_NEWLINES); | |
| 606 | +$td->runtest("convert to qdf", | |
| 607 | + {$td->COMMAND => | |
| 608 | + "qpdf --qdf b.pdf b.qdf" . | |
| 609 | + " --password=owner --no-original-object-ids"}, | |
| 610 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 611 | +$td->runtest("compare qdf", | |
| 612 | + {$td->COMMAND => "sh ./diff-ignore-ID-version a.qdf b.qdf"}, | |
| 613 | + {$td->STRING => "okay\n", $td->EXIT_STATUS => 0}, | |
| 614 | + $td->NORMALIZE_NEWLINES); | |
| 615 | +$td->runtest("copy encryption with qpdf", | |
| 616 | + {$td->COMMAND => | |
| 617 | + "qpdf --copy-encryption=a.pdf". | |
| 618 | + " --encryption-file-password=user" . | |
| 619 | + " minimal.pdf c.pdf"}, | |
| 620 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 621 | + $td->NORMALIZE_NEWLINES); | |
| 622 | +$td->runtest("check output encryption", | |
| 623 | + {$td->COMMAND => "qpdf --show-encryption c.pdf --password=owner"}, | |
| 624 | + {$td->FILE => "copied-encryption.out", | |
| 625 | + $td->EXIT_STATUS => 0}, | |
| 626 | + $td->NORMALIZE_NEWLINES); | |
| 627 | +$td->runtest("convert to qdf", | |
| 628 | + {$td->COMMAND => | |
| 629 | + "qpdf --qdf c.pdf c.qdf" . | |
| 630 | + " --password=owner --no-original-object-ids"}, | |
| 631 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 632 | +$td->runtest("compare qdf", | |
| 633 | + {$td->COMMAND => "sh ./diff-ignore-ID-version a.qdf c.qdf"}, | |
| 634 | + {$td->STRING => "okay\n", $td->EXIT_STATUS => 0}, | |
| 635 | + $td->NORMALIZE_NEWLINES); | |
| 636 | + | |
| 637 | +# Files with attachments | |
| 638 | +my @attachments = ( | |
| 639 | + 'enc-XI-attachments-base.pdf', | |
| 640 | + 'enc-XI-R6,V5,U=attachment,encrypted-attachments.pdf', | |
| 641 | + 'enc-XI-R6,V5,U=view,attachments,cleartext-metadata.pdf'); | |
| 642 | +$n_tests += 4 * @attachments + 3; | |
| 643 | +foreach my $f (@attachments) | |
| 644 | +{ | |
| 645 | + my $pass = ''; | |
| 646 | + my $tpass = ''; | |
| 647 | + if ($f =~ m/U=([^,\.]+)/) | |
| 648 | + { | |
| 649 | + $pass = "--password=$1"; | |
| 650 | + $tpass = $1; | |
| 651 | + } | |
| 652 | + $td->runtest("decrypt $f", | |
| 653 | + {$td->COMMAND => "qpdf --decrypt $pass $f a.pdf"}, | |
| 654 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 655 | + $td->runtest("extract attachments", | |
| 656 | + {$td->COMMAND => "test_driver 35 a.pdf"}, | |
| 657 | + {$td->FILE => "attachments.out", $td->EXIT_STATUS => 0}, | |
| 658 | + $td->NORMALIZE_NEWLINES); | |
| 659 | + $td->runtest("copy $f", | |
| 660 | + {$td->COMMAND => "qpdf $pass $f a.pdf"}, | |
| 661 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 662 | + $td->runtest("extract attachments", | |
| 663 | + {$td->COMMAND => "test_driver 35 a.pdf $tpass"}, | |
| 664 | + {$td->FILE => "attachments.out", $td->EXIT_STATUS => 0}, | |
| 665 | + $td->NORMALIZE_NEWLINES); | |
| 666 | +} | |
| 667 | +$td->runtest("unfilterable with crypt", | |
| 668 | + {$td->COMMAND => | |
| 669 | + "test_driver 36 unfilterable-with-crypt.pdf attachment"}, | |
| 670 | + {$td->FILE => "unfilterable-with-crypt-before.out", | |
| 671 | + $td->EXIT_STATUS => 0}, | |
| 672 | + $td->NORMALIZE_NEWLINES); | |
| 673 | +unlink "a.pdf"; | |
| 674 | +$td->runtest("decrypt file", | |
| 675 | + {$td->COMMAND => "qpdf -decrypt --password=attachment" . | |
| 676 | + " unfilterable-with-crypt.pdf a.pdf"}, | |
| 677 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 678 | +$td->runtest("copy of unfilterable with crypt", | |
| 679 | + {$td->COMMAND => | |
| 680 | + "test_driver 36 a.pdf attachment"}, | |
| 681 | + {$td->FILE => "unfilterable-with-crypt-after.out", | |
| 682 | + $td->EXIT_STATUS => 0}, | |
| 683 | + $td->NORMALIZE_NEWLINES); | |
| 684 | + | |
| 685 | +# Raw encryption key | |
| 686 | +my @enc_key = (['user', '--password=user3'], | |
| 687 | + ['owner', '--password=owner3'], | |
| 688 | + ['hex', '--password-is-hex-key --password=35ea16a48b6a3045133b69ac0906c2e8fb0a2cc97903ae17b51a5786ebdba020']); | |
| 689 | +$n_tests += scalar(@enc_key); | |
| 690 | +foreach my $d (@enc_key) | |
| 691 | +{ | |
| 692 | + my ($description, $pass) = @$d; | |
| 693 | + $td->runtest("use/show encryption key ($description)", | |
| 694 | + {$td->COMMAND => | |
| 695 | + "qpdf --check --show-encryption-key c-r5-in.pdf $pass"}, | |
| 696 | + {$td->FILE => "c-r5-key-$description.out", $td->EXIT_STATUS => 0}, | |
| 697 | + $td->NORMALIZE_NEWLINES); | |
| 698 | +} | |
| 699 | + | |
| 700 | +# Miscellaneous encryption tests | |
| 701 | +$n_tests += 3; | |
| 702 | + | |
| 703 | +$td->runtest("set encryption before set filename", | |
| 704 | + {$td->COMMAND => "test_driver 63 minimal.pdf"}, | |
| 705 | + {$td->STRING => "test 63 done\n", $td->EXIT_STATUS => 0}, | |
| 706 | + $td->NORMALIZE_NEWLINES); | |
| 707 | +$td->runtest("check file's validity", | |
| 708 | + {$td->COMMAND => "qpdf --check --password=u a.pdf"}, | |
| 709 | + {$td->FILE => "encrypt-before-filename.out", | |
| 710 | + $td->EXIT_STATUS => 0}, | |
| 711 | + $td->NORMALIZE_NEWLINES); | |
| 712 | +$td->runtest("handle missing/invalid Length", | |
| 713 | + {$td->COMMAND => "qpdf --check bad-encryption-length.pdf"}, | |
| 714 | + {$td->FILE => "bad-encryption-length.out", | |
| 715 | + $td->EXIT_STATUS => 0}, | |
| 716 | + $td->NORMALIZE_NEWLINES); | |
| 717 | + | |
| 718 | +cleanup(); | |
| 719 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/encryption_parameters.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('encryption_parameters'); | |
| 16 | + | |
| 17 | +my $n_tests = 13; | |
| 18 | + | |
| 19 | +# Encrypt files whose /ID strings are other than 32 bytes long (bug | |
| 20 | +# 2991412). Also linearize these files, which was reported in a | |
| 21 | +# separate bug by email. | |
| 22 | +foreach my $file (qw(short-id long-id)) | |
| 23 | +{ | |
| 24 | + $td->runtest("encrypt $file.pdf", | |
| 25 | + {$td->COMMAND => | |
| 26 | + "qpdf --allow-weak-crypto". | |
| 27 | + " --encrypt '' pass 40 -- $file.pdf a.pdf"}, | |
| 28 | + {$td->STRING => "", | |
| 29 | + $td->EXIT_STATUS => 0}, | |
| 30 | + $td->NORMALIZE_NEWLINES); | |
| 31 | + | |
| 32 | + $td->runtest("check $file.pdf", | |
| 33 | + {$td->COMMAND => "qpdf --check --show-encryption-key a.pdf"}, | |
| 34 | + {$td->FILE => "$file-check.out", | |
| 35 | + $td->EXIT_STATUS => 0}, | |
| 36 | + $td->NORMALIZE_NEWLINES); | |
| 37 | + | |
| 38 | + $td->runtest("linearize $file.pdf", | |
| 39 | + {$td->COMMAND => | |
| 40 | + "qpdf --deterministic-id --linearize $file.pdf a.pdf"}, | |
| 41 | + {$td->STRING => "", | |
| 42 | + $td->EXIT_STATUS => 0}, | |
| 43 | + $td->NORMALIZE_NEWLINES); | |
| 44 | + | |
| 45 | + $td->runtest("check output", | |
| 46 | + {$td->FILE => "a.pdf"}, | |
| 47 | + {$td->FILE => "$file-linearized.pdf"}); | |
| 48 | + | |
| 49 | + $td->runtest("check $file.pdf", | |
| 50 | + {$td->COMMAND => "qpdf --check a.pdf"}, | |
| 51 | + {$td->FILE => "$file-linearized-check.out", | |
| 52 | + $td->EXIT_STATUS => 0}, | |
| 53 | + $td->NORMALIZE_NEWLINES); | |
| 54 | +} | |
| 55 | + | |
| 56 | +# A user provided a file that was missing /ID in its trailer even | |
| 57 | +# though it is encrypted and also has a space instead of a newline | |
| 58 | +# after its xref keyword. This file has those same properties. | |
| 59 | +$td->runtest("check broken file", | |
| 60 | + {$td->COMMAND => "qpdf --check invalid-id-xref.pdf"}, | |
| 61 | + {$td->FILE => "invalid-id-xref.out", $td->EXIT_STATUS => 3}, | |
| 62 | + $td->NORMALIZE_NEWLINES); | |
| 63 | + | |
| 64 | +# A file was emailed privately with issue 96. short-O-U.pdf was | |
| 65 | +# created by copying encryption parameters from that file. It exhibits | |
| 66 | +# the same behavior as the original file. | |
| 67 | +$td->runtest("short /O or /U", | |
| 68 | + {$td->COMMAND => | |
| 69 | + "qpdf --password=19723102477 --check short-O-U.pdf"}, | |
| 70 | + {$td->FILE => "short-O-U.out", | |
| 71 | + $td->EXIT_STATUS => 0}, | |
| 72 | + $td->NORMALIZE_NEWLINES); | |
| 73 | + | |
| 74 | +# A file was sent to me privately as part of issue 212. This file was | |
| 75 | +# encrypted and had /R=3 and /V=1 and was using a 40-bit key. qpdf was | |
| 76 | +# failing to work properly on files with /R=3 and 40-bit keys. The | |
| 77 | +# test file is not this private file, but the encryption parameters | |
| 78 | +# were copied from it. Like the bug file, qpdf < 8.1 can't decrypt it. | |
| 79 | +$td->runtest("/R 3 with 40-bit key", | |
| 80 | + {$td->COMMAND => | |
| 81 | + "qpdf --password=623 --check --show-encryption-key" . | |
| 82 | + " encrypted-40-bit-R3.pdf"}, | |
| 83 | + {$td->FILE => "encrypted-40-bit-R3.out", | |
| 84 | + $td->EXIT_STATUS => 0}, | |
| 85 | + $td->NORMALIZE_NEWLINES); | |
| 86 | + | |
| 87 | +cleanup(); | |
| 88 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/error_condition.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('error_condition'); | |
| 16 | + | |
| 17 | +my $n_tests = 0; | |
| 18 | +# $n_tests incremented after initialization of badfiles below. | |
| 19 | + | |
| 20 | +my @badfiles = ("not a PDF file", # 1 | |
| 21 | + "no startxref", # 2 | |
| 22 | + "bad primary xref offset", # 3 | |
| 23 | + "invalid xref syntax", # 4 | |
| 24 | + "invalid xref entry", # 5 | |
| 25 | + "free table inconsistency", # 6 | |
| 26 | + "no trailer dictionary", # 7 | |
| 27 | + "bad secondary xref", # 8 | |
| 28 | + "no /Size in trailer", # 9 | |
| 29 | + "/Size not integer", # 10 | |
| 30 | + "/Prev not integer", # 11 | |
| 31 | + "/Size inconsistency", # 12 | |
| 32 | + "bad {", # 13 | |
| 33 | + "bad }", # 14 | |
| 34 | + "bad ]", # 15 | |
| 35 | + "bad >>", # 16 | |
| 36 | + "dictionary errors", # 17 | |
| 37 | + "bad )", # 18 | |
| 38 | + "bad >", # 19 | |
| 39 | + "invalid hexstring character", # 20 | |
| 40 | + "invalid name token", # 21 | |
| 41 | + "no /Length for stream dictionary", # 22 | |
| 42 | + "/Length not integer", # 23 | |
| 43 | + "expected endstream", # 24 | |
| 44 | + "bad obj declaration (objid)", # 25 | |
| 45 | + "bad obj declaration (generation)", # 26 | |
| 46 | + "bad obj declaration (obj)", # 27 | |
| 47 | + "expected endobj", # 28 | |
| 48 | + "null in name", # 29 | |
| 49 | + "invalid stream /Filter", # 30 | |
| 50 | + "unknown stream /Filter", # 31 | |
| 51 | + "obj/gen mismatch", # 32 | |
| 52 | + "invalid stream /Filter and xref", # 33 | |
| 53 | + "obj/gen in wrong place", # 34 | |
| 54 | + "object stream of wrong type", # 35 | |
| 55 | + "bad dictionary key", # 36 | |
| 56 | + "space before xref", # 37 | |
| 57 | + "startxref to space then eof", # 38 | |
| 58 | + ); | |
| 59 | + | |
| 60 | +$n_tests += @badfiles + 8; | |
| 61 | + | |
| 62 | +# Test 6 contains errors in the free table consistency, but we no | |
| 63 | +# longer have any consistency check for this since it is not important | |
| 64 | +# neither Acrobat nor other PDF viewers really care. Tests 12 and 28 | |
| 65 | +# have error conditions that used to be fatal but are now considered | |
| 66 | +# non-fatal. | |
| 67 | +my %badtest_overrides = (); | |
| 68 | +for(6, 12..15, 17, 18..32, 34..37) | |
| 69 | +{ | |
| 70 | + $badtest_overrides{$_} = 0; | |
| 71 | +} | |
| 72 | + | |
| 73 | +for (my $i = 1; $i <= scalar(@badfiles); ++$i) | |
| 74 | +{ | |
| 75 | + my $status = $badtest_overrides{$i}; | |
| 76 | + $status = 2 unless defined $status; | |
| 77 | + $td->runtest($badfiles[$i-1], | |
| 78 | + {$td->COMMAND => "test_driver 0 bad$i.pdf"}, | |
| 79 | + {$td->FILE => "bad$i.out", | |
| 80 | + $td->EXIT_STATUS => $status}, | |
| 81 | + $td->NORMALIZE_NEWLINES); | |
| 82 | +} | |
| 83 | + | |
| 84 | +$td->runtest("Suppress warnings", | |
| 85 | + {$td->COMMAND => "qpdf --no-warn bad14.pdf a.pdf"}, | |
| 86 | + {$td->STRING => "", $td->EXIT_STATUS => 3}); | |
| 87 | +$td->runtest("Suppress warnings", | |
| 88 | + {$td->COMMAND => | |
| 89 | + "qpdf --no-warn --warning-exit-0 bad14.pdf a.pdf"}, | |
| 90 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 91 | +$td->runtest("Suppress warnings with --check", | |
| 92 | + {$td->COMMAND => "qpdf --check --no-warn bad14.pdf"}, | |
| 93 | + {$td->FILE => "bad14-check-no-warn.out", | |
| 94 | + $td->EXIT_STATUS => 3}, | |
| 95 | + $td->NORMALIZE_NEWLINES); | |
| 96 | +$td->runtest("C API: errors", | |
| 97 | + {$td->COMMAND => "qpdf-ctest 2 bad1.pdf '' a.pdf"}, | |
| 98 | + {$td->FILE => "c-read-errors.out", | |
| 99 | + $td->EXIT_STATUS => 0}, | |
| 100 | + $td->NORMALIZE_NEWLINES); | |
| 101 | +$td->runtest("C API: warnings writing", | |
| 102 | + {$td->COMMAND => "qpdf-ctest 2 bad33.pdf '' a.pdf"}, | |
| 103 | + {$td->FILE => "c-write-warnings.out", | |
| 104 | + $td->EXIT_STATUS => 0}, | |
| 105 | + $td->NORMALIZE_NEWLINES); | |
| 106 | +$td->runtest("C API: no recovery", | |
| 107 | + {$td->COMMAND => "qpdf-ctest 10 bad33.pdf '' a.pdf"}, | |
| 108 | + {$td->FILE => "c-no-recovery.out", | |
| 109 | + $td->EXIT_STATUS => 0}, | |
| 110 | + $td->NORMALIZE_NEWLINES); | |
| 111 | + | |
| 112 | +$td->runtest("integer type checks", | |
| 113 | + {$td->COMMAND => "test_driver 62 minimal.pdf"}, | |
| 114 | + {$td->STRING => "test 62 done\n", $td->EXIT_STATUS => 0}, | |
| 115 | + $td->NORMALIZE_NEWLINES); | |
| 116 | +$td->runtest("getValueAs... accessor checks", | |
| 117 | + {$td->COMMAND => "test_driver 85 -"}, | |
| 118 | + {$td->STRING => "test 85 done\n", $td->EXIT_STATUS => 0}, | |
| 119 | + $td->NORMALIZE_NEWLINES); | |
| 120 | + | |
| 121 | +$n_tests += @badfiles + 11; | |
| 122 | + | |
| 123 | +# Recovery tests. These are mostly after-the-fact -- when recovery | |
| 124 | +# was implemented, some degree of recovery was possible on many of the | |
| 125 | +# files. Mostly the recovery does not actually repair the error, | |
| 126 | +# though in some cases it may. Acrobat Reader would not be able to | |
| 127 | +# recover any of these files any better. | |
| 128 | +my %recover_failures = (); | |
| 129 | +for (1, 7, 16) | |
| 130 | +{ | |
| 131 | + $recover_failures{$_} = 1; | |
| 132 | +} | |
| 133 | +for (my $i = 1; $i <= scalar(@badfiles); ++$i) | |
| 134 | +{ | |
| 135 | + my $status = 0; | |
| 136 | + if (exists $recover_failures{$i}) | |
| 137 | + { | |
| 138 | + $status = 2; | |
| 139 | + } | |
| 140 | + $td->runtest("recover " . $badfiles[$i-1], | |
| 141 | + {$td->COMMAND => "test_driver 1 bad$i.pdf"}, | |
| 142 | + {$td->FILE => "bad$i-recover.out", | |
| 143 | + $td->EXIT_STATUS => $status}, | |
| 144 | + $td->NORMALIZE_NEWLINES); | |
| 145 | +} | |
| 146 | + | |
| 147 | +# See if we can recover the cross reference table on a file that has | |
| 148 | +# been appended to even when it deletes and reuses objects. We can't | |
| 149 | +# completely do it in the case of deleted objects, but we can get | |
| 150 | +# mostly there. | |
| 151 | +$td->runtest("good replaced page contents", | |
| 152 | + {$td->COMMAND => | |
| 153 | + "qpdf --static-id -qdf --no-original-object-ids" . | |
| 154 | + " append-page-content.pdf a.pdf"}, | |
| 155 | + {$td->STRING => "", | |
| 156 | + $td->EXIT_STATUS => 0}, | |
| 157 | + $td->NORMALIZE_NEWLINES); | |
| 158 | +$td->runtest("check output", | |
| 159 | + {$td->FILE => "a.pdf"}, | |
| 160 | + {$td->FILE => "append-page-content-good.qdf"}); | |
| 161 | +$td->runtest("damaged replaced page contents", | |
| 162 | + {$td->COMMAND => | |
| 163 | + "qpdf --static-id -qdf --no-original-object-ids" . | |
| 164 | + " append-page-content-damaged.pdf a.pdf"}, | |
| 165 | + {$td->FILE => "append-page-content-damaged.out", | |
| 166 | + $td->EXIT_STATUS => 3}, | |
| 167 | + $td->NORMALIZE_NEWLINES); | |
| 168 | +$td->runtest("check output", | |
| 169 | + {$td->FILE => "a.pdf"}, | |
| 170 | + {$td->FILE => "append-page-content-damaged.qdf"}); | |
| 171 | +$td->runtest("run check on damaged file", | |
| 172 | + {$td->COMMAND => "qpdf --check append-page-content-damaged.pdf"}, | |
| 173 | + {$td->FILE => "append-page-content-damaged-check.out", | |
| 174 | + $td->EXIT_STATUS => 3}, | |
| 175 | + $td->NORMALIZE_NEWLINES); | |
| 176 | +$td->runtest("check with C API", | |
| 177 | + {$td->COMMAND => | |
| 178 | + "qpdf-ctest 1 append-page-content-damaged.pdf '' ''"}, | |
| 179 | + {$td->FILE => "append-page-content-damaged-c-check.out", | |
| 180 | + $td->EXIT_STATUS => 0}, | |
| 181 | + $td->NORMALIZE_NEWLINES); | |
| 182 | + | |
| 183 | +$td->runtest("recoverable xref errors", | |
| 184 | + {$td->COMMAND => | |
| 185 | + "qpdf --check --show-xref xref-errors.pdf"}, | |
| 186 | + {$td->FILE => "xref-errors.out", | |
| 187 | + $td->EXIT_STATUS => 3}, | |
| 188 | + $td->NORMALIZE_NEWLINES); | |
| 189 | + | |
| 190 | +$td->runtest("xref loop with append", | |
| 191 | + {$td->COMMAND => | |
| 192 | + "qpdf --deterministic-id append-xref-loop.pdf a.pdf"}, | |
| 193 | + {$td->FILE => "append-xref-loop.out", | |
| 194 | + $td->EXIT_STATUS => 3}, | |
| 195 | + $td->NORMALIZE_NEWLINES); | |
| 196 | +$td->runtest("check output", | |
| 197 | + {$td->FILE => "a.pdf"}, | |
| 198 | + {$td->FILE => "append-xref-loop-fixed.pdf"}); | |
| 199 | + | |
| 200 | +$td->runtest("endobj not at newline", | |
| 201 | + {$td->COMMAND => | |
| 202 | + "qpdf --deterministic-id endobj-at-eol.pdf a.pdf"}, | |
| 203 | + {$td->FILE => "endobj-at-eol.out", | |
| 204 | + $td->EXIT_STATUS => 3}, | |
| 205 | + $td->NORMALIZE_NEWLINES); | |
| 206 | +$td->runtest("check output", | |
| 207 | + {$td->FILE => "a.pdf"}, | |
| 208 | + {$td->FILE => "endobj-at-eol-fixed.pdf"}); | |
| 209 | + | |
| 210 | +cleanup(); | |
| 211 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/exceptions.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('exceptions'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("check exception handling", | |
| 20 | + {$td->COMMAND => "test_driver 61 -"}, | |
| 21 | + {$td->FILE => "exceptions.out", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("check certain exception types", | |
| 24 | + {$td->COMMAND => "test_driver 81 -"}, | |
| 25 | + {$td->STRING => "test 81 done\n", $td->EXIT_STATUS => 0}, | |
| 26 | + $td->NORMALIZE_NEWLINES); | |
| 27 | + | |
| 28 | +cleanup(); | |
| 29 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/extensions_dictionary.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('extensions_dictionary'); | |
| 16 | + | |
| 17 | +my @ext_inputs = ('minimal.pdf', 'extensions-adbe.pdf', | |
| 18 | + 'extensions-other.pdf', 'extensions-adbe-other.pdf'); | |
| 19 | +my @new_versions = ('1.3', '1.6', '1.7.1', '1.7.2', '1.7.3', | |
| 20 | + '1.8', '1.8.0', '1.8.2', '1.8.5'); | |
| 21 | +my $n_tests = (4 * @new_versions + 3) * @ext_inputs; | |
| 22 | +foreach my $input (@ext_inputs) | |
| 23 | +{ | |
| 24 | + my $base = $input; | |
| 25 | + $base =~ s/\.pdf$//; | |
| 26 | + if ($base eq 'minimal') | |
| 27 | + { | |
| 28 | + $base = 'extensions-none'; | |
| 29 | + } | |
| 30 | + foreach my $version (@new_versions) | |
| 31 | + { | |
| 32 | + foreach my $op (qw(min force)) | |
| 33 | + { | |
| 34 | + $td->runtest("$input: $op version to $version", | |
| 35 | + {$td->COMMAND => | |
| 36 | + "qpdf --static-id" . | |
| 37 | + " --$op-version=$version $input a.pdf"}, | |
| 38 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 39 | + $td->runtest("check version information ($op $version)", | |
| 40 | + {$td->COMMAND => "test_driver 34 a.pdf"}, | |
| 41 | + {$td->FILE => "$base-$op-$version.out", | |
| 42 | + $td->EXIT_STATUS => 0}, | |
| 43 | + $td->NORMALIZE_NEWLINES); | |
| 44 | + if (($op eq 'force') && ($version eq '1.8.5')) | |
| 45 | + { | |
| 46 | + # Look at the actual file for a few cases to make sure | |
| 47 | + # qdf and non-qdf output are okay | |
| 48 | + $td->runtest("check file", | |
| 49 | + {$td->FILE => "a.pdf"}, | |
| 50 | + {$td->FILE => "$base-$op-$version.pdf"}); | |
| 51 | + $td->runtest("$input: $op version to $version", | |
| 52 | + {$td->COMMAND => | |
| 53 | + "qpdf --qdf --static-id" . | |
| 54 | + " --$op-version=$version $input a.qdf"}, | |
| 55 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 56 | + $td->runtest("check file", | |
| 57 | + {$td->FILE => "a.qdf"}, | |
| 58 | + {$td->FILE => "$base-$op-$version.qdf"}); | |
| 59 | + } | |
| 60 | + } | |
| 61 | + } | |
| 62 | +} | |
| 63 | +cleanup(); | |
| 64 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/extraction.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('extraction'); | |
| 16 | + | |
| 17 | +my $n_tests = 13; | |
| 18 | + | |
| 19 | +$td->runtest("show xref", | |
| 20 | + {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 21 | + " --show-xref"}, | |
| 22 | + {$td->FILE => "show-xref.out", | |
| 23 | + $td->EXIT_STATUS => 0}, | |
| 24 | + $td->NORMALIZE_NEWLINES); | |
| 25 | + | |
| 26 | +$td->runtest("show pages", | |
| 27 | + {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 28 | + " --show-pages"}, | |
| 29 | + {$td->FILE => "show-pages.out", | |
| 30 | + $td->EXIT_STATUS => 0}, | |
| 31 | + $td->NORMALIZE_NEWLINES); | |
| 32 | + | |
| 33 | +$td->runtest("show-pages-images", | |
| 34 | + {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 35 | + " --show-pages --with-images"}, | |
| 36 | + {$td->FILE => "show-pages-images.out", | |
| 37 | + $td->EXIT_STATUS => 0}, | |
| 38 | + $td->NORMALIZE_NEWLINES); | |
| 39 | + | |
| 40 | +$td->runtest("show-pages-images", | |
| 41 | + {$td->COMMAND => "qpdf shared-images.pdf" . | |
| 42 | + " --show-pages --with-images"}, | |
| 43 | + {$td->FILE => "shared-images-show.out", | |
| 44 | + $td->EXIT_STATUS => 0}, | |
| 45 | + $td->NORMALIZE_NEWLINES); | |
| 46 | + | |
| 47 | +$td->runtest("show-page-1", | |
| 48 | + {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 49 | + " --show-object=5,0"}, | |
| 50 | + {$td->FILE => "show-page-1.out", | |
| 51 | + $td->EXIT_STATUS => 0}, | |
| 52 | + $td->NORMALIZE_NEWLINES); | |
| 53 | + | |
| 54 | +$td->runtest("show-page-1-content-raw", | |
| 55 | + {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 56 | + " --show-object=7 --raw-stream-data"}, | |
| 57 | + {$td->FILE => "show-page-1-content-raw.out", | |
| 58 | + $td->EXIT_STATUS => 0}); | |
| 59 | + | |
| 60 | +$td->runtest("show-page-1-content-filtered", | |
| 61 | + {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 62 | + " --show-object=7 --filtered-stream-data"}, | |
| 63 | + {$td->FILE => "show-page-1-content-filtered.out", | |
| 64 | + $td->EXIT_STATUS => 0}); | |
| 65 | + | |
| 66 | +$td->runtest("show-page-1-content-normalized", | |
| 67 | + {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 68 | + " --show-object=7,0 --filtered-stream-data --normalize-content=y"}, | |
| 69 | + {$td->FILE => "show-page-1-content-normalized.out", | |
| 70 | + $td->EXIT_STATUS => 0}); | |
| 71 | + | |
| 72 | +$td->runtest("show-page-1-image", | |
| 73 | + {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 74 | + " --show-object=8 --raw-stream-data"}, | |
| 75 | + {$td->FILE => "show-page-1-image.out", | |
| 76 | + $td->EXIT_STATUS => 0}); | |
| 77 | + | |
| 78 | +$td->runtest("unfilterable stream data", | |
| 79 | + {$td->COMMAND => "qpdf unfilterable.pdf" . | |
| 80 | + " --show-object=4 --filtered-stream-data"}, | |
| 81 | + {$td->FILE => "show-unfilterable.out", | |
| 82 | + $td->EXIT_STATUS => 2}, | |
| 83 | + $td->NORMALIZE_NEWLINES); | |
| 84 | + | |
| 85 | +$td->runtest("show-xref-by-id", | |
| 86 | + {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 87 | + " --show-object=12"}, | |
| 88 | + {$td->FILE => "show-xref-by-id.out", | |
| 89 | + $td->EXIT_STATUS => 0}, | |
| 90 | + $td->NORMALIZE_NEWLINES); | |
| 91 | + | |
| 92 | +$td->runtest("show-xref-by-id-filtered", | |
| 93 | + {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 94 | + " --show-object=12 --filtered-stream-data"}, | |
| 95 | + {$td->FILE => "show-xref-by-id-filtered.out", | |
| 96 | + $td->EXIT_STATUS => 0}); | |
| 97 | + | |
| 98 | +$td->runtest("show trailer", | |
| 99 | + {$td->COMMAND => "qpdf minimal.pdf --show-object=trailer"}, | |
| 100 | + {$td->FILE => "show-trailer.out", | |
| 101 | + $td->EXIT_STATUS => 0}, | |
| 102 | + $td->NORMALIZE_NEWLINES); | |
| 103 | + | |
| 104 | +cleanup(); | |
| 105 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/filter_abbreviations.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('filter_abbreviations'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +# Stream filter abbreviations from table H.1 | |
| 20 | +$td->runtest("stream filter abbreviations", | |
| 21 | + {$td->COMMAND => "qpdf --static-id filter-abbreviation.pdf a.pdf"}, | |
| 22 | + {$td->STRING => "", | |
| 23 | + $td->EXIT_STATUS => 0}, | |
| 24 | + $td->NORMALIZE_NEWLINES); | |
| 25 | +$td->runtest("check output", | |
| 26 | + {$td->FILE => "a.pdf"}, | |
| 27 | + {$td->FILE => "filter-abbreviation.out"}); | |
| 28 | + | |
| 29 | +cleanup(); | |
| 30 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/final_version.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('final_version'); | |
| 16 | + | |
| 17 | +my $n_tests = 1; | |
| 18 | + | |
| 19 | +$td->runtest("check final version", | |
| 20 | + {$td->COMMAND => "test_driver 54 minimal.pdf"}, | |
| 21 | + {$td->STRING => "test 54 done\n", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | + | |
| 24 | +cleanup(); | |
| 25 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/fix_qdf.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('fix_qdf'); | |
| 16 | + | |
| 17 | +my $n_tests = 5; | |
| 18 | + | |
| 19 | +for (my $n = 1; $n <= 2; ++$n) | |
| 20 | +{ | |
| 21 | + $td->runtest("fix-qdf $n", | |
| 22 | + {$td->COMMAND => "fix-qdf fix$n.qdf"}, | |
| 23 | + {$td->FILE => "fix$n.qdf.out", | |
| 24 | + $td->EXIT_STATUS => 0}); | |
| 25 | + | |
| 26 | + $td->runtest("identity fix-qdf $n", | |
| 27 | + {$td->COMMAND => "fix-qdf fix$n.qdf.out"}, | |
| 28 | + {$td->FILE => "fix$n.qdf.out", | |
| 29 | + $td->EXIT_STATUS => 0}); | |
| 30 | +} | |
| 31 | +$td->runtest("fix-qdf with big object stream", # > 255 objects in a stream | |
| 32 | + {$td->COMMAND => "fix-qdf big-ostream.pdf"}, | |
| 33 | + {$td->FILE => "big-ostream.pdf", | |
| 34 | + $td->EXIT_STATUS => 0}); | |
| 35 | + | |
| 36 | +cleanup(); | |
| 37 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/flatten_annotations.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('flatten_annotations'); | |
| 16 | + | |
| 17 | +my $n_tests = 0; | |
| 18 | + | |
| 19 | +# manual-appearances was created by hand-coding appearance streams | |
| 20 | +# with graphics that make it easy to test matrix calculations. The | |
| 21 | +# result of flattening the annotations was compared visually with | |
| 22 | +# okular. Some PDF viewers don't actually display the original version | |
| 23 | +# correctly. The pages are as follows: | |
| 24 | +# - page 1: normal | |
| 25 | +# - page 2: rotate 90 with /F 20 (NoRotate) | |
| 26 | +# - page 3: non-trivial matrix | |
| 27 | +# - page 4: non-trivial matrix, rotate | |
| 28 | +# - page 5: rotate 180 with /F 20 | |
| 29 | +# - page 6: rotate 90, /F 20, non-trivial matrix | |
| 30 | +# - page 7: flags: top is print, middle is screen, bottom is hidden | |
| 31 | +# - page 8: rotate 270 with /F 20 | |
| 32 | +# - page 9: normal -- available for additional testing | |
| 33 | +# | |
| 34 | +# form-filled-by-acrobat was filled in using the Acrobat Reader | |
| 35 | +# android app. One of its appearance streams is actually an image. | |
| 36 | +# | |
| 37 | +# need-appearances.pdf is based on field-types.pdf with manual edits | |
| 38 | +# to turn on NeedAppearances, change /V for several fields, and add | |
| 39 | +# the comment annotation from comment-annotation.pdf. The test output | |
| 40 | +# includes a flattened version of the comment annotation but not of | |
| 41 | +# the form fields. Changes: | |
| 42 | +# - field-types.pdf has /NeedAppearances true | |
| 43 | +# - text1: blank -> abc | |
| 44 | +# - r1: 1 -> 2 | |
| 45 | +# - list1: blank -> five | |
| 46 | +# - combolist1: blank -> pi | |
| 47 | +# - drop1: blank -> elephant | |
| 48 | +# - combodrop1: blank -> delta | |
| 49 | + | |
| 50 | +my @annotation_files = ( | |
| 51 | + 'manual-appearances', | |
| 52 | + 'form-filled-by-acrobat', | |
| 53 | + 'comment-annotation', | |
| 54 | + 'comment-annotation-direct', | |
| 55 | + 'sample-form', | |
| 56 | + 'need-appearances', | |
| 57 | + 'need-appearances-more', | |
| 58 | + ); | |
| 59 | +$n_tests += 2 * scalar(@annotation_files); | |
| 60 | + | |
| 61 | +foreach my $f (@annotation_files) | |
| 62 | +{ | |
| 63 | + my $exp_out = {$td->STRING => "", $td->EXIT_STATUS => 0}; | |
| 64 | + if (-f "$f-warn.out") | |
| 65 | + { | |
| 66 | + $exp_out = {$td->FILE => "$f-warn.out", $td->EXIT_STATUS => 3}; | |
| 67 | + } | |
| 68 | + $td->runtest("flatten $f", | |
| 69 | + {$td->COMMAND => | |
| 70 | + "qpdf --qdf --static-id --no-original-object-ids" . | |
| 71 | + " --flatten-annotations=all $f.pdf a.pdf"}, | |
| 72 | + $exp_out, | |
| 73 | + $td->NORMALIZE_NEWLINES); | |
| 74 | + $td->runtest("check output", | |
| 75 | + {$td->FILE => "a.pdf"}, | |
| 76 | + {$td->FILE => "$f-out.pdf"}); | |
| 77 | +} | |
| 78 | + | |
| 79 | +$n_tests += 4; | |
| 80 | +foreach my $f (qw(screen print)) | |
| 81 | +{ | |
| 82 | + $td->runtest("flatten for $f", | |
| 83 | + {$td->COMMAND => | |
| 84 | + "qpdf --qdf --static-id --no-original-object-ids" . | |
| 85 | + " --flatten-annotations=$f manual-appearances.pdf a.pdf"}, | |
| 86 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 87 | + $td->NORMALIZE_NEWLINES); | |
| 88 | + $td->runtest("check output", | |
| 89 | + {$td->FILE => "a.pdf"}, | |
| 90 | + {$td->FILE => "manual-appearances-$f-out.pdf"}); | |
| 91 | +} | |
| 92 | + | |
| 93 | +cleanup(); | |
| 94 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/form_xobject.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('form_xobject'); | |
| 16 | + | |
| 17 | +my $n_tests = 22; | |
| 18 | + | |
| 19 | +$td->runtest("form xobject creation", | |
| 20 | + {$td->COMMAND => "test_driver 55 fxo-red.pdf"}, | |
| 21 | + {$td->STRING => "test 55 done\n", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("compare files", | |
| 24 | + {$td->FILE => "a.pdf"}, | |
| 25 | + {$td->FILE => "form-xobjects-out.pdf"}); | |
| 26 | +foreach (my $i = 56; $i <= 59; ++$i) | |
| 27 | +{ | |
| 28 | + # See comments in test_driver.cc for a verbal description of what | |
| 29 | + # the resulting files should look like. | |
| 30 | + $td->runtest("overlay transformations", | |
| 31 | + {$td->COMMAND => "test_driver $i fxo-red.pdf fxo-blue.pdf"}, | |
| 32 | + {$td->STRING => "test $i done\n", $td->EXIT_STATUS => 0}, | |
| 33 | + $td->NORMALIZE_NEWLINES); | |
| 34 | + $td->runtest("compare files", | |
| 35 | + {$td->FILE => "a.pdf"}, | |
| 36 | + {$td->FILE => "fx-overlay-$i.pdf"}); | |
| 37 | +} | |
| 38 | +foreach (my $i = 64; $i <= 67; ++$i) | |
| 39 | +{ | |
| 40 | + # See comments in test_driver.cc for a verbal description of what | |
| 41 | + # the resulting files should look like. | |
| 42 | + $td->runtest("overlay shrink/expand", | |
| 43 | + {$td->COMMAND => | |
| 44 | + "test_driver $i fxo-bigsmall.pdf fxo-smallbig.pdf"}, | |
| 45 | + {$td->STRING => "test $i done\n", $td->EXIT_STATUS => 0}, | |
| 46 | + $td->NORMALIZE_NEWLINES); | |
| 47 | + $td->runtest("compare files", | |
| 48 | + {$td->FILE => "a.pdf"}, | |
| 49 | + {$td->FILE => "fx-overlay-$i.pdf"}); | |
| 50 | +} | |
| 51 | + | |
| 52 | +my @uo_cases = ( | |
| 53 | + '--underlay fxo-green.pdf --repeat=z --to=1-14 --' . | |
| 54 | + ' --overlay fxo-blue.pdf --', # 1 | |
| 55 | + '--overlay fxo-green.pdf --from= --repeat=r2,r1 --' . | |
| 56 | + ' --underlay fxo-blue.pdf --from=z-1 --', # 2 | |
| 57 | + '--overlay fxo-green.pdf --from= --repeat=r2,r1 --' . | |
| 58 | + ' --underlay fxo-blue.pdf --from=z-1 -- --coalesce-contents', # 3 | |
| 59 | + '--overlay fxo-green.pdf --', # 4 | |
| 60 | + '--underlay fxo-green.pdf --to=3-7 --', # 5 | |
| 61 | + '--overlay fxo-blue.pdf --to=1,1,1,1 --from=1-4 --' . | |
| 62 | + ' --pages . 1 --', #6 | |
| 63 | + '--overlay 20-pages.pdf --password=user --', #7 | |
| 64 | + ); | |
| 65 | +$n_tests += 2 * scalar(@uo_cases); | |
| 66 | +for (my $i = 1; $i <= scalar(@uo_cases); ++$i) | |
| 67 | +{ | |
| 68 | + my $args = $uo_cases[$i-1]; | |
| 69 | + my $outbase = "uo-$i"; | |
| 70 | + $td->runtest("overlay/underlay $i", | |
| 71 | + {$td->COMMAND => | |
| 72 | + "qpdf --static-id --qdf --no-original-object-ids" . | |
| 73 | + " --verbose fxo-red.pdf a.pdf $args"}, | |
| 74 | + {$td->FILE => "$outbase.out", $td->EXIT_STATUS => 0}, | |
| 75 | + $td->NORMALIZE_NEWLINES); | |
| 76 | + $td->runtest("compare files", | |
| 77 | + {$td->FILE => "a.pdf"}, | |
| 78 | + {$td->FILE => "$outbase.pdf"}); | |
| 79 | +} | |
| 80 | +$td->runtest("foreach", | |
| 81 | + {$td->COMMAND => "test_driver 71 nested-form-xobjects.pdf"}, | |
| 82 | + {$td->FILE => "nested-form-xobjects.out", | |
| 83 | + $td->EXIT_STATUS => 0}, | |
| 84 | + $td->NORMALIZE_NEWLINES); | |
| 85 | +$td->runtest("page operations on form xobject", | |
| 86 | + {$td->COMMAND => "test_driver 72 nested-form-xobjects.pdf"}, | |
| 87 | + {$td->FILE => "page-ops-on-form-xobject.out", | |
| 88 | + $td->EXIT_STATUS => 0}, | |
| 89 | + $td->NORMALIZE_NEWLINES); | |
| 90 | +$td->runtest("overlay on page with no resources", | |
| 91 | + {$td->COMMAND => | |
| 92 | + "qpdf --deterministic-id page-with-no-resources.pdf" . | |
| 93 | + " --overlay minimal.pdf -- a.pdf"}, | |
| 94 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 95 | + $td->NORMALIZE_NEWLINES); | |
| 96 | +$td->runtest("check overlay with no resources output", | |
| 97 | + {$td->FILE => "a.pdf"}, | |
| 98 | + {$td->FILE => "overlay-no-resources.pdf"}); | |
| 99 | + | |
| 100 | +cleanup(); | |
| 101 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/from_scratch.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('from_scratch'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("basic qpdf from scratch", | |
| 20 | + {$td->COMMAND => "pdf_from_scratch 0"}, | |
| 21 | + {$td->STRING => "test 0 done\n", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("check output", | |
| 24 | + {$td->FILE => "a.pdf"}, | |
| 25 | + {$td->FILE => "from-scratch-0.pdf"}); | |
| 26 | +cleanup(); | |
| 27 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/get_xref.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('get_xref'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("without object streams", | |
| 20 | + {$td->COMMAND => "test_xref minimal.pdf"}, | |
| 21 | + {$td->FILE => "minimal-xref.out", | |
| 22 | + $td->EXIT_STATUS => 0}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | + | |
| 25 | +$td->runtest("with object streams", | |
| 26 | + {$td->COMMAND => "test_xref digitally-signed.pdf"}, | |
| 27 | + {$td->FILE => "digitally-signed-xref.out", | |
| 28 | + $td->EXIT_STATUS => 0}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | + | |
| 31 | +cleanup(); | |
| 32 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/image_optimization.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('image_optimization'); | |
| 16 | + | |
| 17 | +my @image_opt = ( | |
| 18 | + ['image-streams', 'image-streams', ''], | |
| 19 | + ['small-images', 'defaults', ''], | |
| 20 | + ['small-images', 'min-width', | |
| 21 | + '--oi-min-width=150 --oi-min-height=0 --oi-min-area=0'], | |
| 22 | + ['small-images', 'min-height', | |
| 23 | + '--oi-min-width=0 --oi-min-height=150 --oi-min-area=0'], | |
| 24 | + ['small-images', 'min-area', | |
| 25 | + '--oi-min-width=0 --oi-min-height=0 --oi-min-area=30000'], | |
| 26 | + ['small-images', 'min-area-all', | |
| 27 | + '--oi-min-width=0 --oi-min-height=0 --oi-min-area=30000'], | |
| 28 | + ['large-inline-image', 'inline-images', | |
| 29 | + '--ii-min-bytes=0'], | |
| 30 | + ['large-inline-image', 'inline-images-all-size', | |
| 31 | + '--oi-min-width=0 --oi-min-height=0 --oi-min-area=0 --ii-min-bytes=0'], | |
| 32 | + ['large-inline-image', 'inline-images-keep-some', ''], | |
| 33 | + ['large-inline-image', 'inline-images-keep-all', '--keep-inline-images'], | |
| 34 | + ['unsupported-optimization', 'unsupported', | |
| 35 | + '--oi-min-width=0 --oi-min-height=0 --oi-min-area=0'], | |
| 36 | + ); | |
| 37 | + | |
| 38 | +my $n_tests = 2 * scalar(@image_opt); | |
| 39 | + | |
| 40 | +foreach my $d (@image_opt) | |
| 41 | +{ | |
| 42 | + my ($f, $description, $args) = @$d; | |
| 43 | + | |
| 44 | + $td->runtest("optimize images: $description", | |
| 45 | + {$td->COMMAND => | |
| 46 | + "qpdf --static-id --optimize-images --verbose" . | |
| 47 | + " $args $f.pdf a.pdf", | |
| 48 | + $td->FILTER => "perl filter-optimize-images.pl"}, | |
| 49 | + {$td->FILE => "optimize-images-$description.out", | |
| 50 | + $td->EXIT_STATUS => 0}, | |
| 51 | + $td->NORMALIZE_NEWLINES); | |
| 52 | + $td->runtest("check json: $description", | |
| 53 | + {$td->COMMAND => "qpdf --json --json-key=pages a.pdf"}, | |
| 54 | + {$td->FILE => "optimize-images-$description-json.out", | |
| 55 | + $td->EXIT_STATUS => 0}, | |
| 56 | + $td->NORMALIZE_NEWLINES); | |
| 57 | +} | |
| 58 | + | |
| 59 | +cleanup(); | |
| 60 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/inline_images.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | +use Digest::MD5; | |
| 6 | +use File::Copy; | |
| 7 | + | |
| 8 | +unshift(@INC, '.'); | |
| 9 | +require qpdf_test_helpers; | |
| 10 | + | |
| 11 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 12 | + | |
| 13 | +require TestDriver; | |
| 14 | + | |
| 15 | +cleanup(); | |
| 16 | + | |
| 17 | +my $td = new TestDriver('inline_images'); | |
| 18 | + | |
| 19 | +my $n_compare_pdfs = 0; | |
| 20 | +my $n_tests = 10; | |
| 21 | + | |
| 22 | +# The file large-inline-image.pdf is a hand-crafted file with several | |
| 23 | +# inline images of various sizes including one that is two megabytes, | |
| 24 | +# encoded in base85, and has a base85-encoding that contains EI | |
| 25 | +# surrounded by delimiters several times. This exercises the EI | |
| 26 | +# detection code added in qpdf 8.4. | |
| 27 | + | |
| 28 | +$td->runtest("complex inline image parsing", | |
| 29 | + {$td->COMMAND => | |
| 30 | + "qpdf --qdf --static-id large-inline-image.pdf a.pdf"}, | |
| 31 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 32 | + $td->NORMALIZE_NEWLINES); | |
| 33 | +$td->runtest("check output", | |
| 34 | + {$td->FILE => "a.pdf"}, | |
| 35 | + {$td->FILE => "large-inline-image.qdf"}); | |
| 36 | + | |
| 37 | +$td->runtest("eof in inline image", | |
| 38 | + {$td->COMMAND => | |
| 39 | + "qpdf --qdf --static-id eof-in-inline-image.pdf a.pdf"}, | |
| 40 | + {$td->FILE => "eof-inline-qdf.out", $td->EXIT_STATUS => 3}, | |
| 41 | + $td->NORMALIZE_NEWLINES); | |
| 42 | +$td->runtest("check output", | |
| 43 | + {$td->FILE => "a.pdf"}, | |
| 44 | + {$td->FILE => "eof-in-inline-image.qdf"}); | |
| 45 | +$td->runtest("externalize eof in inline image", | |
| 46 | + {$td->COMMAND => | |
| 47 | + "qpdf --qdf --externalize-inline-images" . | |
| 48 | + " --static-id eof-in-inline-image.pdf a.pdf"}, | |
| 49 | + {$td->FILE => "eof-inline-qdf.out", $td->EXIT_STATUS => 3}, | |
| 50 | + $td->NORMALIZE_NEWLINES); | |
| 51 | +$td->runtest("check output", | |
| 52 | + {$td->FILE => "a.pdf"}, | |
| 53 | + {$td->FILE => "eof-in-inline-image-ii.qdf"}); | |
| 54 | +$td->runtest("externalize damaged image", | |
| 55 | + {$td->COMMAND => | |
| 56 | + "qpdf --externalize-inline-images" . | |
| 57 | + " --compress-streams=n --static-id" . | |
| 58 | + " damaged-inline-image.pdf a.pdf"}, | |
| 59 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 60 | + $td->NORMALIZE_NEWLINES); | |
| 61 | +$td->runtest("check output", | |
| 62 | + {$td->FILE => "a.pdf"}, | |
| 63 | + {$td->FILE => "damaged-inline-image-out.pdf"}); | |
| 64 | +$td->runtest("named colorspace", | |
| 65 | + {$td->COMMAND => | |
| 66 | + "qpdf --static-id --externalize-inline-images" . | |
| 67 | + " --ii-min-bytes=0 inline-image-colorspace-lookup.pdf a.pdf"}, | |
| 68 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 69 | + $td->NORMALIZE_NEWLINES); | |
| 70 | +$td->runtest("check output", | |
| 71 | + {$td->FILE => "a.pdf"}, | |
| 72 | + {$td->FILE => "inline-image-colorspace-lookup-out.pdf"}); | |
| 73 | + | |
| 74 | + | |
| 75 | +my @eii_tests = ( | |
| 76 | + ['inline-images', 80], | |
| 77 | + ['large-inline-image', 1024], | |
| 78 | + ['nested-form-xobjects-inline-images', 20], | |
| 79 | + ); | |
| 80 | +$n_tests += 4 * scalar(@eii_tests); | |
| 81 | +$n_compare_pdfs += 2 * scalar(@eii_tests); | |
| 82 | + | |
| 83 | +foreach my $d (@eii_tests) | |
| 84 | +{ | |
| 85 | + my ($file, $threshold) = @$d; | |
| 86 | + $td->runtest("inline image $file (all)", | |
| 87 | + {$td->COMMAND => | |
| 88 | + "qpdf --qdf --static-id --externalize-inline-images" . | |
| 89 | + " --ii-min-bytes=0 $file.pdf a.pdf"}, | |
| 90 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 91 | + $td->NORMALIZE_NEWLINES); | |
| 92 | + $td->runtest("check output", | |
| 93 | + {$td->FILE => "a.pdf"}, | |
| 94 | + {$td->FILE => "$file-ii-all.pdf"}); | |
| 95 | + compare_pdfs($td, "$file.pdf", "a.pdf"); | |
| 96 | + | |
| 97 | + $td->runtest("inline image $file (some)", | |
| 98 | + {$td->COMMAND => | |
| 99 | + "qpdf --qdf --static-id --externalize-inline-images" . | |
| 100 | + " --ii-min-bytes=$threshold $file.pdf a.pdf"}, | |
| 101 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 102 | + $td->NORMALIZE_NEWLINES); | |
| 103 | + $td->runtest("check output", | |
| 104 | + {$td->FILE => "a.pdf"}, | |
| 105 | + {$td->FILE => "$file-ii-some.pdf"}); | |
| 106 | + compare_pdfs($td, "$file.pdf", "a.pdf"); | |
| 107 | +} | |
| 108 | + | |
| 109 | +cleanup(); | |
| 110 | +$td->report(calc_ntests($n_tests, $n_compare_pdfs)); | ... | ... |
qpdf/qtest/interactive_form.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('interactive_form'); | |
| 16 | + | |
| 17 | +my @form_tests = ( | |
| 18 | + 'minimal', | |
| 19 | + 'form-empty-from-odt', | |
| 20 | + 'form-mod1', | |
| 21 | + # Atril (MATE Document Viewer) 1.20.1 dumps appearance streams | |
| 22 | + # when modifying form fields, leaving /NeedAppearances true. | |
| 23 | + 'form-filled-with-atril', | |
| 24 | + 'form-bad-fields-array', | |
| 25 | + 'form-errors', | |
| 26 | + 'form-document-defaults', | |
| 27 | + ); | |
| 28 | + | |
| 29 | +my $n_tests = scalar(@form_tests) + 6; | |
| 30 | + | |
| 31 | +# Many of the form*.pdf files were created by converting the | |
| 32 | +# LibreOffice document storage/form.odt to PDF and then manually | |
| 33 | +# modifying the resulting PDF in various ways. That file would be good | |
| 34 | +# starting point for generation of more complex forms should that be | |
| 35 | +# required in the future. The file storage/form.pdf is a direct export | |
| 36 | +# from LibreOffice with no modifications. The files | |
| 37 | +# storage/field-types.odt and storage/field-types.pdf are the basis of | |
| 38 | +# field-types.pdf used elsewhere in the test suite. | |
| 39 | + | |
| 40 | +foreach my $f (@form_tests) | |
| 41 | +{ | |
| 42 | + $td->runtest("form test: $f", | |
| 43 | + {$td->COMMAND => "test_driver 43 $f.pdf"}, | |
| 44 | + {$td->FILE => "form-$f.out", $td->EXIT_STATUS => 0}, | |
| 45 | + $td->NORMALIZE_NEWLINES); | |
| 46 | +} | |
| 47 | + | |
| 48 | +$td->runtest("fill fields", | |
| 49 | + {$td->COMMAND => "test_driver 44 form-no-need-appearances.pdf"}, | |
| 50 | + {$td->FILE => "form-no-need-appearances.out", | |
| 51 | + $td->EXIT_STATUS => 0}, | |
| 52 | + $td->NORMALIZE_NEWLINES); | |
| 53 | +$td->runtest("compare files", | |
| 54 | + {$td->FILE => "a.pdf"}, | |
| 55 | + {$td->FILE => "form-no-need-appearances-filled.pdf"}); | |
| 56 | + | |
| 57 | +$td->runtest("button fields", | |
| 58 | + {$td->COMMAND => "test_driver 51 button-set.pdf"}, | |
| 59 | + {$td->FILE => "button-set.out", $td->EXIT_STATUS => 0}, | |
| 60 | + $td->NORMALIZE_NEWLINES); | |
| 61 | +$td->runtest("compare files", | |
| 62 | + {$td->FILE => "a.pdf"}, | |
| 63 | + {$td->FILE => "button-set-out.pdf"}); | |
| 64 | + | |
| 65 | +$td->runtest("broken button fields", | |
| 66 | + {$td->COMMAND => "test_driver 51 button-set-broken.pdf"}, | |
| 67 | + {$td->FILE => "button-set-broken.out", $td->EXIT_STATUS => 0}, | |
| 68 | + $td->NORMALIZE_NEWLINES); | |
| 69 | +$td->runtest("compare files", | |
| 70 | + {$td->FILE => "a.pdf"}, | |
| 71 | + {$td->FILE => "button-set-broken-out.pdf"}); | |
| 72 | + | |
| 73 | +cleanup(); | |
| 74 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/invalid_objects.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('invalid_objects'); | |
| 16 | + | |
| 17 | +my $n_tests = 3; | |
| 18 | + | |
| 19 | +$td->runtest("closed input source", | |
| 20 | + {$td->COMMAND => "test_driver 73 minimal.pdf"}, | |
| 21 | + {$td->FILE => "test73.out", | |
| 22 | + $td->EXIT_STATUS => 2}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | + | |
| 25 | +$td->runtest("empty object", | |
| 26 | + {$td->COMMAND => "qpdf -show-object=7,0 empty-object.pdf"}, | |
| 27 | + {$td->FILE => "empty-object.out", | |
| 28 | + $td->EXIT_STATUS => 3}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | + | |
| 31 | +$td->runtest("object with zero offset", | |
| 32 | + {$td->COMMAND => "qpdf --check zero-offset.pdf"}, | |
| 33 | + {$td->FILE => "zero-offset.out", $td->EXIT_STATUS => 3}, | |
| 34 | + $td->NORMALIZE_NEWLINES); | |
| 35 | + | |
| 36 | +cleanup(); | |
| 37 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/json.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | +use File::Compare; | |
| 6 | + | |
| 7 | +unshift(@INC, '.'); | |
| 8 | +require qpdf_test_helpers; | |
| 9 | + | |
| 10 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 11 | + | |
| 12 | +require TestDriver; | |
| 13 | + | |
| 14 | +cleanup(); | |
| 15 | + | |
| 16 | +my $td = new TestDriver('json'); | |
| 17 | + | |
| 18 | +my @json_files = ( | |
| 19 | + ['outlines-with-actions', []], | |
| 20 | + ['outlines-with-old-root-dests', []], | |
| 21 | + ['page-labels-and-outlines', []], | |
| 22 | + ['page-labels-num-tree', []], | |
| 23 | + ['image-streams', []], | |
| 24 | + ['image-streams-small', []], | |
| 25 | + ['field-types', []], | |
| 26 | + ['field-types', ['--show-encryption-key']], | |
| 27 | + ['image-streams', ['--decode-level=all']], | |
| 28 | + ['image-streams', ['--decode-level=specialized']], | |
| 29 | + ['page-labels-and-outlines', ['--json-key=qpdf']], | |
| 30 | + ['page-labels-and-outlines', ['--json-key=pages']], | |
| 31 | + ['page-labels-and-outlines', ['--json-key=pagelabels']], | |
| 32 | + ['page-labels-and-outlines', ['--json-key=outlines']], | |
| 33 | + ['page-labels-and-outlines', | |
| 34 | + ['--json-key=outlines', '--json-key=pages']], | |
| 35 | + ['page-labels-and-outlines', | |
| 36 | + ['--json-key=qpdf', '--json-object=trailer']], | |
| 37 | + ['page-labels-and-outlines', | |
| 38 | + ['--json-key=qpdf', '--json-object=trailer', '--json-object=2 0 R']], | |
| 39 | + ['field-types', ['--json-key=acroform']], | |
| 40 | + ['need-appearances', ['--json-key=acroform']], | |
| 41 | + ['V4-aes', ['--json-key=encrypt']], | |
| 42 | + ['V4-aes', ['--json-key=encrypt', '--show-encryption-key']], | |
| 43 | +); | |
| 44 | +my $n_tests = 25 + (2 * scalar(@json_files)); | |
| 45 | +foreach my $d (@json_files) | |
| 46 | +{ | |
| 47 | + my ($file, $xargs) = @$d; | |
| 48 | + my $out = "json-$file"; | |
| 49 | + my @v1_xargs = (); | |
| 50 | + foreach my $x (@$xargs) | |
| 51 | + { | |
| 52 | + my $y = $x; | |
| 53 | + $y =~ s/^.*=//; | |
| 54 | + $y =~ s/\s.*//; | |
| 55 | + $out .= "-$y"; | |
| 56 | + if ($x eq '--json-key=qpdf') | |
| 57 | + { | |
| 58 | + push(@v1_xargs, '--json-key=objects'); | |
| 59 | + } | |
| 60 | + else | |
| 61 | + { | |
| 62 | + push(@v1_xargs, $x); | |
| 63 | + } | |
| 64 | + } | |
| 65 | + my $in = "$file.pdf"; | |
| 66 | + $td->runtest("json v1 $out", | |
| 67 | + {$td->COMMAND => | |
| 68 | + ['qpdf', '--json=1', '--test-json-schema', | |
| 69 | + @v1_xargs, $in]}, | |
| 70 | + {$td->FILE => "$out-v1.out", $td->EXIT_STATUS => 0}, | |
| 71 | + $td->NORMALIZE_NEWLINES); | |
| 72 | + $td->runtest("json v2 $out", | |
| 73 | + {$td->COMMAND => | |
| 74 | + ['qpdf', '--json=2', '--test-json-schema', @$xargs, $in]}, | |
| 75 | + {$td->FILE => "$out-v2.out", $td->EXIT_STATUS => 0}, | |
| 76 | + $td->NORMALIZE_NEWLINES); | |
| 77 | +} | |
| 78 | + | |
| 79 | +$td->runtest("bad json stream data (inline)", | |
| 80 | + {$td->COMMAND => | |
| 81 | + "qpdf --json=2 --test-json-schema" . | |
| 82 | + " --json-stream-data=inline bad-data.pdf > a.json"}, | |
| 83 | + {$td->FILE => "bad-data-json.out", $td->EXIT_STATUS => 3}, | |
| 84 | + $td->NORMALIZE_NEWLINES); | |
| 85 | +$td->runtest("check (inline)", | |
| 86 | + {$td->FILE => "a.json"}, | |
| 87 | + {$td->FILE => "json-bad-data-json-inline-v2.out"}, | |
| 88 | + $td->NORMALIZE_NEWLINES); | |
| 89 | +$td->runtest("bad json stream data (file)", | |
| 90 | + {$td->COMMAND => | |
| 91 | + "qpdf --json=2 --test-json-schema" . | |
| 92 | + " --json-stream-data=file --json-stream-prefix=auto" . | |
| 93 | + " bad-data.pdf > a.json"}, | |
| 94 | + {$td->FILE => "bad-data-json.out", $td->EXIT_STATUS => 3}, | |
| 95 | + $td->NORMALIZE_NEWLINES); | |
| 96 | +$td->runtest("check (file)", | |
| 97 | + {$td->FILE => "a.json"}, | |
| 98 | + {$td->FILE => "json-bad-data-json-file-v2.out"}, | |
| 99 | + $td->NORMALIZE_NEWLINES); | |
| 100 | +$td->runtest("check stream (file)", | |
| 101 | + {$td->FILE => "auto-4"}, | |
| 102 | + {$td->FILE => "bad-data-4.out"}); | |
| 103 | + | |
| 104 | +foreach my $l (qw(none generalized specialized all)) | |
| 105 | +{ | |
| 106 | + if ($l ne 'all') | |
| 107 | + { | |
| 108 | + # We don't want a dependency on the exact value of the | |
| 109 | + # uncompressed jpeg, which can differ depending on which jpeg | |
| 110 | + # library is use. | |
| 111 | + $td->runtest("image-streams json inline: $l", | |
| 112 | + {$td->COMMAND => | |
| 113 | + "qpdf image-streams-small.pdf --json=2" . | |
| 114 | + " --decode-level=$l --json-stream-data=inline"}, | |
| 115 | + {$td->FILE => "json-image-streams-$l-inline-v2.out", | |
| 116 | + $td->EXIT_STATUS => 0}, | |
| 117 | + $td->NORMALIZE_NEWLINES); | |
| 118 | + } | |
| 119 | + $td->runtest("image-streams json file: $l", | |
| 120 | + {$td->COMMAND => | |
| 121 | + "qpdf image-streams-small.pdf --json=2" . | |
| 122 | + " --decode-level=$l --json-stream-data=file" . | |
| 123 | + " --json-stream-prefix=auto --json-key=qpdf" . | |
| 124 | + " --json-object=12 --json-object=16 --json-object=18"}, | |
| 125 | + {$td->FILE => "json-image-streams-$l-file-v2.out", | |
| 126 | + $td->EXIT_STATUS => 0}, | |
| 127 | + $td->NORMALIZE_NEWLINES); | |
| 128 | + # object 12: /FlateDecode | |
| 129 | + # object 16: /DCTDecode | |
| 130 | + # object 18: /RunLengthDecode | |
| 131 | + my %exp_compression = ( | |
| 132 | + '12' => {'none' => 1}, | |
| 133 | + '16' => {'none' => 1, 'generalized' => 1, 'specialized' => 1}, | |
| 134 | + '18' => {'none' => 1, 'generalized' => 1}, | |
| 135 | + ); | |
| 136 | + | |
| 137 | + foreach my $obj (qw(12 16 18)) | |
| 138 | + { | |
| 139 | + my $compressed = (exists $exp_compression{$obj}{$l}); | |
| 140 | + my $suf = $compressed ? "compressed" : "uncompressed"; | |
| 141 | + if (($obj eq '16') && (! $compressed)) | |
| 142 | + { | |
| 143 | + # Rather than testing the uncompressed DCT, just make sure | |
| 144 | + # it is different from the compressed DCT. | |
| 145 | + my $same = (compare( | |
| 146 | + "auto-$obj", | |
| 147 | + "image-streams-small-$obj-compressed.out") ? | |
| 148 | + "same" : "different"); | |
| 149 | + $td->runtest("check stream data ($obj, $l)", | |
| 150 | + {$td->STRING => $same}, | |
| 151 | + {$td->STRING => "same"}); | |
| 152 | + } | |
| 153 | + else | |
| 154 | + { | |
| 155 | + $td->runtest("check stream data ($obj, $l)", | |
| 156 | + {$td->FILE => "auto-$obj"}, | |
| 157 | + {$td->FILE => "image-streams-small-$obj-$suf.out"}); | |
| 158 | + } | |
| 159 | + } | |
| 160 | +} | |
| 161 | + | |
| 162 | +$td->runtest("use --to-json option", | |
| 163 | + {$td->COMMAND => "qpdf --to-json image-streams-small.pdf"}, | |
| 164 | + {$td->FILE => "image-streams-small-to-json.out", | |
| 165 | + $td->EXIT_STATUS => 0}, | |
| 166 | + $td->NORMALIZE_NEWLINES); | |
| 167 | + | |
| 168 | +cleanup(); | |
| 169 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/keep_files_open.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('keep_files_open'); | |
| 16 | + | |
| 17 | +my $n_tests = 4; | |
| 18 | + | |
| 19 | +{ # local scope | |
| 20 | + open(F, "<minimal.pdf") or die; | |
| 21 | + local $/ = undef; | |
| 22 | + binmode F; | |
| 23 | + my $content = <F>; | |
| 24 | + close(F); | |
| 25 | + for (my $i = 1; $i <= 51; ++$i) | |
| 26 | + { | |
| 27 | + open(F, sprintf(">%03d-kfo.pdf", $i)) or die; | |
| 28 | + binmode F; | |
| 29 | + print F $content; | |
| 30 | + close(F); | |
| 31 | + } | |
| 32 | +} | |
| 33 | +$td->runtest("automatic disable keep files open", | |
| 34 | + {$td->COMMAND => | |
| 35 | + "qpdf --verbose --static-id --empty" . | |
| 36 | + " --keep-files-open-threshold=50" . | |
| 37 | + " --pages *kfo.pdf -- a.pdf"}, | |
| 38 | + {$td->FILE => "disable-kfo.out", $td->EXIT_STATUS => 0}, | |
| 39 | + $td->NORMALIZE_NEWLINES); | |
| 40 | +$td->runtest("don't disable keep files open", | |
| 41 | + {$td->COMMAND => | |
| 42 | + "qpdf --verbose --static-id --empty" . | |
| 43 | + " --pages 01*kfo.pdf -- a.pdf"}, | |
| 44 | + {$td->FILE => "enable-kfo.out", $td->EXIT_STATUS => 0}, | |
| 45 | + $td->NORMALIZE_NEWLINES); | |
| 46 | +$td->runtest("explict keep files open", | |
| 47 | + {$td->COMMAND => | |
| 48 | + "qpdf --verbose --static-id --keep-files-open=y --empty" . | |
| 49 | + " --pages 00?-kfo.pdf -- a.pdf"}, | |
| 50 | + {$td->FILE => "kfo-y.out", $td->EXIT_STATUS => 0}, | |
| 51 | + $td->NORMALIZE_NEWLINES); | |
| 52 | +$td->runtest("explicit keep files open = n", | |
| 53 | + {$td->COMMAND => | |
| 54 | + "qpdf --verbose --static-id --keep-files-open=n --empty" . | |
| 55 | + " --pages 00?-kfo.pdf -- a.pdf"}, | |
| 56 | + {$td->FILE => "kfo-n.out", $td->EXIT_STATUS => 0}, | |
| 57 | + $td->NORMALIZE_NEWLINES); | |
| 58 | + | |
| 59 | +cleanup(); | |
| 60 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/large_file.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('large_file'); | |
| 16 | + | |
| 17 | +my $large_file_test_path = $ENV{'QPDF_LARGE_FILE_TEST_PATH'} || undef; | |
| 18 | +if (defined($large_file_test_path)) | |
| 19 | +{ | |
| 20 | + $large_file_test_path = File::Spec->rel2abs($large_file_test_path); | |
| 21 | + $large_file_test_path =~ s!\\!/!g; | |
| 22 | +} | |
| 23 | + | |
| 24 | + | |
| 25 | +my $nlarge = 1; | |
| 26 | +if (defined $large_file_test_path) | |
| 27 | +{ | |
| 28 | + $nlarge = 2; | |
| 29 | +} | |
| 30 | +else | |
| 31 | +{ | |
| 32 | + $td->notify("--- Skipping tests on actual large files ---"); | |
| 33 | +} | |
| 34 | + | |
| 35 | +my $n_tests = $nlarge * 13; | |
| 36 | +for (my $large = 0; $large < $nlarge; ++$large) | |
| 37 | +{ | |
| 38 | + if ($large) | |
| 39 | + { | |
| 40 | + $td->notify("--- Running tests on actual large files ---"); | |
| 41 | + } | |
| 42 | + else | |
| 43 | + { | |
| 44 | + $td->notify("--- Running large file tests on small files ---"); | |
| 45 | + } | |
| 46 | + my $size = ($large ? "large" : "small"); | |
| 47 | + my $file = $large ? "$large_file_test_path/a.pdf" : "a.pdf"; | |
| 48 | + $td->runtest("write test file", | |
| 49 | + {$td->COMMAND => "test_large_file write $size '$file'"}, | |
| 50 | + {$td->FILE => "large_file.out", $td->EXIT_STATUS => 0}, | |
| 51 | + $td->NORMALIZE_NEWLINES); | |
| 52 | + $td->runtest("read test file", | |
| 53 | + {$td->COMMAND => "test_large_file read $size '$file'"}, | |
| 54 | + {$td->FILE => "large_file.out", $td->EXIT_STATUS => 0}, | |
| 55 | + $td->NORMALIZE_NEWLINES); | |
| 56 | + $td->runtest("check", | |
| 57 | + {$td->COMMAND => "qpdf --suppress-recovery --check '$file'", | |
| 58 | + $td->FILTER => "grep -v checking"}, | |
| 59 | + {$td->FILE => "large_file-check-normal.out", | |
| 60 | + $td->EXIT_STATUS => 0}, | |
| 61 | + $td->NORMALIZE_NEWLINES); | |
| 62 | + | |
| 63 | + for my $ostream (0, 1) | |
| 64 | + { | |
| 65 | + for my $linearize (0, 1) | |
| 66 | + { | |
| 67 | + if (($ostream == 0) && ($linearize == 0)) | |
| 68 | + { | |
| 69 | + # Original file has no object streams and is not linearized. | |
| 70 | + next; | |
| 71 | + } | |
| 72 | + my $args = ""; | |
| 73 | + my $omode = $ostream ? "generate" : "disable"; | |
| 74 | + my $lin = $linearize ? "--linearize" : ""; | |
| 75 | + my $newfile = "$file-new"; | |
| 76 | + | |
| 77 | + $td->runtest("transform: ostream=$ostream, linearize=$linearize", | |
| 78 | + {$td->COMMAND => | |
| 79 | + "qpdf --stream-data=preserve" . | |
| 80 | + " --object-streams=$omode" . | |
| 81 | + " $lin '$file' '$newfile'"}, | |
| 82 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 83 | + $td->runtest("read: ostream=$ostream, linearize=$linearize", | |
| 84 | + {$td->COMMAND => | |
| 85 | + "test_large_file read $size '$newfile'"}, | |
| 86 | + {$td->FILE => "large_file.out", $td->EXIT_STATUS => 0}, | |
| 87 | + $td->NORMALIZE_NEWLINES); | |
| 88 | + my $check_out = | |
| 89 | + ($linearize | |
| 90 | + ? ($ostream | |
| 91 | + ? "large_file-check-ostream-linearized.out" | |
| 92 | + : "large_file-check-linearized.out") | |
| 93 | + : ($ostream | |
| 94 | + ? "large_file-check-ostream.out" | |
| 95 | + : "large_file-check-normal.out")); | |
| 96 | + $td->runtest("check: ostream=$ostream, linearize=$linearize", | |
| 97 | + {$td->COMMAND => | |
| 98 | + "qpdf --suppress-recovery --check '$newfile'", | |
| 99 | + $td->FILTER => "grep -v checking"}, | |
| 100 | + {$td->FILE => $check_out, $td->EXIT_STATUS => 0}, | |
| 101 | + $td->NORMALIZE_NEWLINES); | |
| 102 | + unlink $newfile; | |
| 103 | + } | |
| 104 | + } | |
| 105 | + | |
| 106 | + # Clobber xref | |
| 107 | + open(F, "+<$file") or die; | |
| 108 | + seek(F, -50, 2); | |
| 109 | + my $pos = tell F; | |
| 110 | + my $buf; | |
| 111 | + read(F, $buf, 50); | |
| 112 | + die unless $buf =~ m/^(.*startxref\n)\d+/s; | |
| 113 | + $pos += length($1); | |
| 114 | + seek(F, $pos, 0) or die; | |
| 115 | + print F "oops" or die; | |
| 116 | + close(F); | |
| 117 | + | |
| 118 | + my $cmd = +{$td->COMMAND => "test_large_file read $size '$file'"}; | |
| 119 | + if ($large) | |
| 120 | + { | |
| 121 | + $cmd->{$td->FILTER} = "sed -e 's,$large_file_test_path/,,'"; | |
| 122 | + } | |
| 123 | + $td->runtest("reconstruct xref table", | |
| 124 | + $cmd, | |
| 125 | + {$td->FILE => "large_file_xref_reconstruct.out", | |
| 126 | + $td->EXIT_STATUS => 0}, | |
| 127 | + $td->NORMALIZE_NEWLINES); | |
| 128 | + unlink $file; | |
| 129 | +} | |
| 130 | + | |
| 131 | +cleanup(); | |
| 132 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/library_version.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('library_version'); | |
| 16 | + | |
| 17 | +my $n_tests = 3; | |
| 18 | + | |
| 19 | +$td->runtest("qpdf version", | |
| 20 | + {$td->COMMAND => "qpdf --version"}, | |
| 21 | + {$td->REGEXP => ".*qpdf version \\S+\n.*", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("qpdf copyright contains version too", | |
| 24 | + {$td->COMMAND => "qpdf --copyright"}, | |
| 25 | + {$td->REGEXP => "(?s)qpdf version \\S+\n.*Apache.*", | |
| 26 | + $td->EXIT_STATUS => 0}, | |
| 27 | + $td->NORMALIZE_NEWLINES); | |
| 28 | +$td->runtest("C API: qpdf version", | |
| 29 | + {$td->COMMAND => "qpdf-ctest --version"}, | |
| 30 | + {$td->REGEXP => "qpdf-ctest version \\S+\n", | |
| 31 | + $td->EXIT_STATUS => 0}, | |
| 32 | + $td->NORMALIZE_NEWLINES); | |
| 33 | + | |
| 34 | +cleanup(); | |
| 35 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/linearization.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('linearization'); | |
| 16 | + | |
| 17 | +my $n_tests = 0; | |
| 18 | +# $n_tests incremented after initialization of @linearized_files and | |
| 19 | +# @to_linearize. | |
| 20 | + | |
| 21 | +# *'ed files were linearized with Pdlin. | |
| 22 | +my @linearized_files = | |
| 23 | + ('lin0', # not linearized | |
| 24 | + 'lin1', # * outlines, page labels, pdlin | |
| 25 | + 'lin2', # * lin1 with null and newline | |
| 26 | + 'lin3', # same file saved with acrobat | |
| 27 | + 'lin4', # * lin1 with no /PageMode | |
| 28 | + 'lin5', # lin3 with embedded thumbnails | |
| 29 | + 'lin6', # * lin5 with pdlin | |
| 30 | + 'lin7', # lin5 with /PageMode /UseThumbs | |
| 31 | + 'lin8', # * lin7 with pdlin | |
| 32 | + 'lin9', # * shared objects, indirect null | |
| 33 | + 'badlin1', # parameter dictionary errors | |
| 34 | + ); | |
| 35 | + | |
| 36 | +my @to_linearize = | |
| 37 | + ('lin-special', # lots of weird cases -- see file comments | |
| 38 | + 'delete-and-reuse', # deleted, reused objects | |
| 39 | + 'lin-delete-and-reuse', # linearized, then delete and reuse | |
| 40 | + 'object-stream', # contains object streams | |
| 41 | + 'hybrid-xref', # contains both xref tables and streams | |
| 42 | + 'gen1', # has objects with generation > 0 | |
| 43 | + 'direct-outlines', # /Outlines is a direct object | |
| 44 | + @linearized_files, # we should be able to relinearize | |
| 45 | + ); | |
| 46 | + | |
| 47 | +$n_tests += @linearized_files + 6; | |
| 48 | +$n_tests += (3 * @to_linearize * 5) + 6; | |
| 49 | + | |
| 50 | +foreach my $base (@linearized_files) | |
| 51 | +{ | |
| 52 | + $td->runtest("dump linearization: $base", | |
| 53 | + {$td->COMMAND => "qpdf --show-linearization $base.pdf"}, | |
| 54 | + {$td->FILE => "$base.out", | |
| 55 | + $td->EXIT_STATUS => 0}, | |
| 56 | + $td->NORMALIZE_NEWLINES); | |
| 57 | +} | |
| 58 | + | |
| 59 | +# Check normal modified and linearized modified files, making sure | |
| 60 | +# that their qdf files are identical. The next two tests have the | |
| 61 | +# same expected output files and different input files. | |
| 62 | +check_pdf($td, "modified", | |
| 63 | + "qpdf --static-id --qdf --no-original-object-ids" . | |
| 64 | + " delete-and-reuse.pdf", "delete-and-reuse.qdf", | |
| 65 | + 0); | |
| 66 | +check_pdf($td, "linearized and modified", | |
| 67 | + "qpdf --static-id --qdf --no-original-object-ids" . | |
| 68 | + " lin-delete-and-reuse.pdf", "delete-and-reuse.qdf", # same output | |
| 69 | + 0); | |
| 70 | + | |
| 71 | +$td->runtest("check linearized and modified", | |
| 72 | + {$td->COMMAND => "qpdf --check lin-delete-and-reuse.pdf"}, | |
| 73 | + {$td->FILE => "lin-delete-and-reuse-check.out", | |
| 74 | + $td->EXIT_STATUS => 0}, | |
| 75 | + $td->NORMALIZE_NEWLINES); | |
| 76 | +$td->runtest("check multiple modifications", | |
| 77 | + {$td->COMMAND => "qpdf --check delete-and-reuse.pdf"}, | |
| 78 | + {$td->FILE => "delete-and-reuse-check.out", | |
| 79 | + $td->EXIT_STATUS => 0}, | |
| 80 | + $td->NORMALIZE_NEWLINES); | |
| 81 | + | |
| 82 | +foreach my $base (@to_linearize) | |
| 83 | +{ | |
| 84 | + foreach my $omode (qw(disable preserve generate)) | |
| 85 | + { | |
| 86 | + my $oarg = "-object-streams=$omode"; | |
| 87 | + my $sdarg = ""; | |
| 88 | + if (($base eq 'lin-special') || ($base eq 'object-stream')) | |
| 89 | + { | |
| 90 | + $sdarg = "--stream-data=uncompress"; | |
| 91 | + } | |
| 92 | + $td->runtest("linearize $base ($omode)", | |
| 93 | + {$td->COMMAND => | |
| 94 | + "qpdf -linearize $oarg $sdarg" . | |
| 95 | + " --static-id $base.pdf a.pdf"}, | |
| 96 | + {$td->STRING => "", | |
| 97 | + $td->EXIT_STATUS => 0}); | |
| 98 | + $td->runtest("check linearization", | |
| 99 | + {$td->COMMAND => "qpdf --check-linearization a.pdf"}, | |
| 100 | + {$td->STRING => "a.pdf: no linearization errors\n", | |
| 101 | + $td->EXIT_STATUS => 0}, | |
| 102 | + $td->NORMALIZE_NEWLINES); | |
| 103 | + # Relinearizing twice should produce identical results. We | |
| 104 | + # have to do it twice because, if objects changed ordering | |
| 105 | + # during the original linearization, the hint tables won't | |
| 106 | + # exactly match. This is because object identifiers are | |
| 107 | + # inserted into the hint table in their original order since | |
| 108 | + # we don't yet have renumbering information when we compute | |
| 109 | + # the table values. | |
| 110 | + $td->runtest("relinearize $base 1", | |
| 111 | + {$td->COMMAND => | |
| 112 | + "qpdf -linearize $sdarg --static-id a.pdf b.pdf"}, | |
| 113 | + {$td->STRING => "", | |
| 114 | + $td->EXIT_STATUS => 0}); | |
| 115 | + $td->runtest("relinearize $base 2", | |
| 116 | + {$td->COMMAND => | |
| 117 | + "qpdf -linearize $sdarg --static-id b.pdf c.pdf"}, | |
| 118 | + {$td->STRING => "", | |
| 119 | + $td->EXIT_STATUS => 0}); | |
| 120 | + $td->runtest("compare files ($omode)", | |
| 121 | + {$td->FILE => "b.pdf"}, | |
| 122 | + {$td->FILE => "c.pdf"}); | |
| 123 | + if (($base eq 'lin-special') || ($base eq 'object-stream')) | |
| 124 | + { | |
| 125 | + $td->runtest("check $base ($omode)", | |
| 126 | + {$td->FILE => "a.pdf"}, | |
| 127 | + {$td->FILE => "$base.$omode.exp"}); | |
| 128 | + } | |
| 129 | + } | |
| 130 | +} | |
| 131 | + | |
| 132 | +cleanup(); | |
| 133 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/linearize_pass1.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('linearize_pass1'); | |
| 16 | + | |
| 17 | +my $n_tests = 3; | |
| 18 | + | |
| 19 | +$td->runtest("linearize pass 1 file", | |
| 20 | + {$td->COMMAND => "qpdf --linearize --static-id" . | |
| 21 | + " --linearize-pass1=b.pdf minimal.pdf a.pdf"}, | |
| 22 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 23 | +$td->runtest("check output", | |
| 24 | + {$td->FILE => "a.pdf"}, | |
| 25 | + {$td->FILE => "minimal-linearized.pdf"}); | |
| 26 | +$td->runtest("check pass1 file", | |
| 27 | + {$td->FILE => "b.pdf"}, | |
| 28 | + {$td->FILE => "minimal-linearize-pass1.pdf"}); | |
| 29 | + | |
| 30 | +cleanup(); | |
| 31 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/merge_and_split.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('merge_and_split'); | |
| 16 | + | |
| 17 | +my $n_tests = 28; | |
| 18 | + | |
| 19 | +# Select pages from the same file multiple times including selecting | |
| 20 | +# twice from an encrypted file and specifying the password only the | |
| 21 | +# first time. The file 20-pages.pdf is specified with two different | |
| 22 | +# paths to duplicate a page. | |
| 23 | +my $pages_options = "--pages page-labels-and-outlines.pdf 1,3,5-7,z" . | |
| 24 | + " 20-pages.pdf --password=user z-15" . | |
| 25 | + " page-labels-and-outlines.pdf 12" . | |
| 26 | + " 20-pages.pdf 10" . | |
| 27 | + " ./20-pages.pdf --password=owner 10" . | |
| 28 | + " minimal.pdf 1 --"; | |
| 29 | + | |
| 30 | +$td->runtest("merge three files", | |
| 31 | + {$td->COMMAND => "qpdf page-labels-and-outlines.pdf a.pdf" . | |
| 32 | + " $pages_options --static-id --verbose --progress", | |
| 33 | + $td->FILTER => "perl filter-progress.pl"}, | |
| 34 | + {$td->FILE => "verbose-merge.out", $td->EXIT_STATUS => 0}, | |
| 35 | + $td->NORMALIZE_NEWLINES); | |
| 36 | +# Manually verified about this file: make sure that outline entries | |
| 37 | +# that pointed to pages that were preserved still work in the copy, | |
| 38 | +# and verify that all pages are as expected. page-labels-and-outlines | |
| 39 | +# as well as 20-pages have text on page n (from 1) that shows its page | |
| 40 | +# position from 0, so page 1 says it's page 0. | |
| 41 | +$td->runtest("check output", | |
| 42 | + {$td->FILE => "a.pdf"}, | |
| 43 | + {$td->FILE => "merge-three-files-1.pdf"}); | |
| 44 | +# Select the same pages but add them to an empty file | |
| 45 | +$td->runtest("merge three files", | |
| 46 | + {$td->COMMAND => "qpdf --empty a.pdf" . | |
| 47 | + " $pages_options --static-id"}, | |
| 48 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 49 | +# Manually verified about this file: it has the same pages but does | |
| 50 | +# not contain outlines or other things from the original file. | |
| 51 | +$td->runtest("check output", | |
| 52 | + {$td->FILE => "a.pdf"}, | |
| 53 | + {$td->FILE => "merge-three-files-2.pdf"}); | |
| 54 | +$td->runtest("avoid respecification of password", | |
| 55 | + {$td->COMMAND => | |
| 56 | + "qpdf --empty a.pdf --copy-encryption=20-pages.pdf" . | |
| 57 | + " --allow-weak-crypto" . | |
| 58 | + " --encryption-file-password=user" . | |
| 59 | + " --pages 20-pages.pdf 1,z -- --static-id"}, | |
| 60 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 61 | +$td->runtest("check output", | |
| 62 | + {$td->FILE => "a.pdf"}, | |
| 63 | + {$td->FILE => "pages-copy-encryption.pdf"}); | |
| 64 | +$td->runtest("merge with implicit ranges", | |
| 65 | + {$td->COMMAND => | |
| 66 | + "qpdf --empty a.pdf" . | |
| 67 | + " --pages minimal.pdf 20-pages.pdf --password=user" . | |
| 68 | + " page-labels-and-outlines.pdf --" . | |
| 69 | + " --static-id"}, | |
| 70 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 71 | +$td->runtest("check output", | |
| 72 | + {$td->FILE => "a.pdf"}, | |
| 73 | + {$td->FILE => "merge-implicit-ranges.pdf"}); | |
| 74 | +$td->runtest("merge with . and implicit ranges", | |
| 75 | + {$td->COMMAND => | |
| 76 | + "qpdf minimal.pdf a.pdf --pages minimal.pdf . 1 --" . | |
| 77 | + " --static-id"}, | |
| 78 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 79 | +$td->runtest("check output", | |
| 80 | + {$td->FILE => "a.pdf"}, | |
| 81 | + {$td->FILE => "merge-dot-implicit-ranges.pdf"}); | |
| 82 | +$td->runtest("merge with multiple labels", | |
| 83 | + {$td->COMMAND => | |
| 84 | + "qpdf --empty a.pdf" . | |
| 85 | + " --pages 11-pages-with-labels.pdf 8-11" . | |
| 86 | + " minimal.pdf " . | |
| 87 | + " page-labels-and-outlines.pdf 17-19 --" . | |
| 88 | + " --static-id"}, | |
| 89 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 90 | +$td->runtest("check output", | |
| 91 | + {$td->FILE => "a.pdf"}, | |
| 92 | + {$td->FILE => "merge-multiple-labels.pdf"}); | |
| 93 | +$td->runtest("remove labels", | |
| 94 | + {$td->COMMAND => | |
| 95 | + "qpdf --empty a.pdf" . | |
| 96 | + " --remove-page-labels" . | |
| 97 | + " --pages 11-pages-with-labels.pdf 8-11" . | |
| 98 | + " minimal.pdf " . | |
| 99 | + " page-labels-and-outlines.pdf 17-19 --" . | |
| 100 | + " --static-id"}, | |
| 101 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 102 | +$td->runtest("check output", | |
| 103 | + {$td->FILE => "a.pdf"}, | |
| 104 | + {$td->FILE => "remove-labels.pdf"}); | |
| 105 | + | |
| 106 | +$td->runtest("split with shared resources", | |
| 107 | + {$td->COMMAND => | |
| 108 | + "qpdf --qdf --static-id" . | |
| 109 | + " --remove-unreferenced-resources=yes" . | |
| 110 | + " shared-images.pdf --pages . 1,3" . | |
| 111 | + " ./shared-images.pdf 1,2 -- a.pdf"}, | |
| 112 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 113 | +$td->runtest("check output", | |
| 114 | + {$td->FILE => "a.pdf"}, | |
| 115 | + {$td->FILE => "shared-images-pages-out.pdf"}); | |
| 116 | + | |
| 117 | +$td->runtest("split with really shared resources", | |
| 118 | + {$td->COMMAND => | |
| 119 | + "qpdf --qdf --static-id" . | |
| 120 | + " --remove-unreferenced-resources=yes" . | |
| 121 | + " shared-images.pdf --pages . 1,3" . | |
| 122 | + " . 1,2 -- a.pdf"}, | |
| 123 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 124 | +$td->runtest("check output", | |
| 125 | + {$td->FILE => "a.pdf"}, | |
| 126 | + {$td->FILE => "really-shared-images-pages-out.pdf"}); | |
| 127 | + | |
| 128 | +$td->runtest("shared resources relevant errors", | |
| 129 | + {$td->COMMAND => | |
| 130 | + "qpdf --qdf --static-id" . | |
| 131 | + " shared-images-errors.pdf --pages . 2 -- a.pdf"}, | |
| 132 | + {$td->FILE => "shared-images-errors-2.out", | |
| 133 | + $td->EXIT_STATUS => 3}, | |
| 134 | + $td->NORMALIZE_NEWLINES); | |
| 135 | +$td->runtest("check output", | |
| 136 | + {$td->FILE => "a.pdf"}, | |
| 137 | + {$td->FILE => "shared-images-errors-2-out.pdf"}); | |
| 138 | + | |
| 139 | +# This test used to generate warnings about images on pages we didn't | |
| 140 | +# care about, but qpdf was modified not to process those pages, so the | |
| 141 | +# "irrelevant" errors went away. | |
| 142 | +$td->runtest("shared resources irrelevant errors", | |
| 143 | + {$td->COMMAND => | |
| 144 | + "qpdf --qdf --static-id" . | |
| 145 | + " shared-images-errors.pdf --pages . 1 -- a.pdf"}, | |
| 146 | + {$td->STRING => "", | |
| 147 | + $td->EXIT_STATUS => 0}, | |
| 148 | + $td->NORMALIZE_NEWLINES); | |
| 149 | +$td->runtest("check output", | |
| 150 | + {$td->FILE => "a.pdf"}, | |
| 151 | + {$td->FILE => "shared-images-errors-1-out.pdf"}); | |
| 152 | + | |
| 153 | +$td->runtest("don't remove shared resources", | |
| 154 | + {$td->COMMAND => | |
| 155 | + "qpdf --qdf --static-id --preserve-unreferenced-resources" . | |
| 156 | + " shared-images.pdf --pages . 1,3 -- a.pdf"}, | |
| 157 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 158 | +$td->runtest("check output", | |
| 159 | + {$td->FILE => "a.pdf"}, | |
| 160 | + {$td->FILE => "shared-images-errors-1-3-out.pdf"}); | |
| 161 | + | |
| 162 | +$td->runtest("duplicate pages", | |
| 163 | + {$td->COMMAND => | |
| 164 | + "qpdf --qdf --static-id 11-pages-with-labels.pdf" . | |
| 165 | + " --pages . 6,5,6 . 5 minimal.pdf 1,1 minimal.pdf 1 --" . | |
| 166 | + " a.pdf"}, | |
| 167 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 168 | +$td->runtest("check output", | |
| 169 | + {$td->FILE => "a.pdf"}, | |
| 170 | + {$td->FILE => "duplicate-pages.pdf"}); | |
| 171 | + | |
| 172 | +# See https://github.com/qpdf/qpdf/issues/399 -- we don't want to | |
| 173 | +# break this, especially if we ever implement deduplication of | |
| 174 | +# identical streams. | |
| 175 | +$td->runtest("force full page duplication", | |
| 176 | + {$td->COMMAND => "qpdf --static-id minimal.pdf" . | |
| 177 | + " --pages . ./minimal.pdf -- a.pdf"}, | |
| 178 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 179 | + $td->NORMALIZE_NEWLINES); | |
| 180 | +$td->runtest("check output", | |
| 181 | + {$td->FILE => "a.pdf"}, | |
| 182 | + {$td->FILE => "deep-duplicate-pages.pdf"}); | |
| 183 | + | |
| 184 | + | |
| 185 | +cleanup(); | |
| 186 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/merge_dictionary.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('merge_dictionary'); | |
| 16 | + | |
| 17 | +my $n_tests = 3; | |
| 18 | + | |
| 19 | +$td->runtest("merge dictionary", | |
| 20 | + {$td->COMMAND => "test_driver 50 merge-dict.pdf"}, | |
| 21 | + {$td->FILE => "merge-dict.out", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("unique resource name", | |
| 24 | + {$td->COMMAND => "test_driver 60 minimal.pdf"}, | |
| 25 | + {$td->FILE => "test60.out", $td->EXIT_STATUS => 0}, | |
| 26 | + $td->NORMALIZE_NEWLINES); | |
| 27 | +$td->runtest("check output", | |
| 28 | + {$td->FILE => "a.pdf"}, | |
| 29 | + {$td->FILE => "unique-resources.pdf"}); | |
| 30 | + | |
| 31 | +cleanup(); | |
| 32 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/multiple_indirection.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('multiple_indirection'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +# Handle file with object stream containing an unreferenced object | |
| 20 | +# that in turn contains an indirect scalar (bug 2974522). | |
| 21 | +$td->runtest("unreferenced indirect scalar", | |
| 22 | + {$td->COMMAND => | |
| 23 | + "qpdf --qdf --static-id --preserve-unreferenced" . | |
| 24 | + " --object-streams=preserve" . | |
| 25 | + " unreferenced-indirect-scalar.pdf a.qdf"}, | |
| 26 | + {$td->STRING => "", | |
| 27 | + $td->EXIT_STATUS => 0}, | |
| 28 | + $td->NORMALIZE_NEWLINES); | |
| 29 | +$td->runtest("check output", | |
| 30 | + {$td->FILE => "a.qdf"}, | |
| 31 | + {$td->FILE => "unreferenced-indirect-scalar.out"}); | |
| 32 | + | |
| 33 | +cleanup(); | |
| 34 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/mutability.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('mutability'); | |
| 16 | + | |
| 17 | +my $n_tests = 5; | |
| 18 | + | |
| 19 | +$td->runtest("no normalization", | |
| 20 | + {$td->COMMAND => "test_driver 4 test4-1.pdf"}, | |
| 21 | + {$td->FILE => "test4-1.qdf", | |
| 22 | + $td->EXIT_STATUS => 0}); | |
| 23 | + | |
| 24 | +$td->runtest("object ordering", | |
| 25 | + {$td->COMMAND => "test_driver 4 test4-4.pdf"}, | |
| 26 | + {$td->FILE => "test4-4.qdf", | |
| 27 | + $td->EXIT_STATUS => 0}); | |
| 28 | + | |
| 29 | +$td->runtest("make direct with allow_streams", | |
| 30 | + {$td->COMMAND => "test_driver 4 test4-5.pdf"}, | |
| 31 | + {$td->FILE => "test4-5.qdf", | |
| 32 | + $td->EXIT_STATUS => 0}); | |
| 33 | + | |
| 34 | +$td->runtest("stream detected", | |
| 35 | + {$td->COMMAND => "test_driver 4 test4-2.pdf"}, | |
| 36 | + {$td->FILE => "test4-2.out", | |
| 37 | + $td->EXIT_STATUS => 2}, | |
| 38 | + $td->NORMALIZE_NEWLINES); | |
| 39 | + | |
| 40 | +$td->runtest("loop detected", | |
| 41 | + {$td->COMMAND => "test_driver 4 test4-3.pdf"}, | |
| 42 | + {$td->FILE => "test4-3.out", | |
| 43 | + $td->EXIT_STATUS => 2}, | |
| 44 | + $td->NORMALIZE_NEWLINES); | |
| 45 | + | |
| 46 | +cleanup(); | |
| 47 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/name_normalization.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('name_normalization'); | |
| 16 | + | |
| 17 | +my $n_tests = 6; | |
| 18 | + | |
| 19 | +$td->runtest("check pound in name", | |
| 20 | + {$td->COMMAND => | |
| 21 | + "test_driver 1 pound-in-name.pdf"}, | |
| 22 | + {$td->FILE => "pound-in-name.out", | |
| 23 | + $td->EXIT_STATUS => 0}, | |
| 24 | + $td->NORMALIZE_NEWLINES); | |
| 25 | +$td->runtest("convert pound in name", | |
| 26 | + {$td->COMMAND => "qpdf --static-id --qdf" . | |
| 27 | + " pound-in-name.pdf a.pdf"}, | |
| 28 | + {$td->FILE => "pound-in-name-qdf.out", | |
| 29 | + $td->EXIT_STATUS => 3}, | |
| 30 | + $td->NORMALIZE_NEWLINES); | |
| 31 | +$td->runtest("check output", | |
| 32 | + {$td->FILE => "a.pdf"}, | |
| 33 | + {$td->FILE => "pound-in-name.qdf"}); | |
| 34 | + | |
| 35 | +$td->runtest("check pound in image names", | |
| 36 | + {$td->COMMAND => | |
| 37 | + "qpdf --check name-pound-images.pdf"}, | |
| 38 | + {$td->FILE => "name-pound-images.out", | |
| 39 | + $td->EXIT_STATUS => 3}, | |
| 40 | + $td->NORMALIZE_NEWLINES); | |
| 41 | +$td->runtest("convert pound in image names", | |
| 42 | + {$td->COMMAND => "qpdf --static-id --qdf" . | |
| 43 | + " name-pound-images.pdf a.pdf"}, | |
| 44 | + {$td->FILE => "name-pound-images-qdf.out", | |
| 45 | + $td->EXIT_STATUS => 3}, | |
| 46 | + $td->NORMALIZE_NEWLINES); | |
| 47 | +$td->runtest("check output", | |
| 48 | + {$td->FILE => "a.pdf"}, | |
| 49 | + {$td->FILE => "name-pound-images.qdf"}); | |
| 50 | + | |
| 51 | +cleanup(); | |
| 52 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/name_number_trees.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('name_number_trees'); | |
| 16 | + | |
| 17 | +my $n_tests = 6; | |
| 18 | + | |
| 19 | +$td->runtest("number trees", | |
| 20 | + {$td->COMMAND => "test_driver 46 number-tree.pdf"}, | |
| 21 | + {$td->FILE => "number-tree.out", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("name trees", | |
| 24 | + {$td->COMMAND => "test_driver 48 name-tree.pdf"}, | |
| 25 | + {$td->FILE => "name-tree.out", $td->EXIT_STATUS => 0}, | |
| 26 | + $td->NORMALIZE_NEWLINES); | |
| 27 | +$td->runtest("nntree split", | |
| 28 | + {$td->COMMAND => "test_driver 74 split-nntree.pdf"}, | |
| 29 | + {$td->FILE => "split-nntree.out", $td->EXIT_STATUS => 0}, | |
| 30 | + $td->NORMALIZE_NEWLINES); | |
| 31 | +$td->runtest("check file", | |
| 32 | + {$td->FILE => "a.pdf"}, | |
| 33 | + {$td->FILE => "split-nntree-out.pdf"}); | |
| 34 | +$td->runtest("nntree erase", | |
| 35 | + {$td->COMMAND => "test_driver 75 erase-nntree.pdf"}, | |
| 36 | + {$td->FILE => "erase-nntree.out", $td->EXIT_STATUS => 0}, | |
| 37 | + $td->NORMALIZE_NEWLINES); | |
| 38 | +$td->runtest("check file", | |
| 39 | + {$td->FILE => "a.pdf"}, | |
| 40 | + {$td->FILE => "erase-nntree-out.pdf"}); | |
| 41 | + | |
| 42 | +cleanup(); | |
| 43 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/newline_before_endstream.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('newline_before_endstream'); | |
| 16 | + | |
| 17 | +my $n_tests = 12; | |
| 18 | + | |
| 19 | +# From issue 133, http://verapdf.org/software/ is an open source | |
| 20 | +# package that can verify PDF/A compliance. This could potentially be | |
| 21 | +# useful for manual or automated verification that qpdf doesn't break | |
| 22 | +# PDF/A compliance should that ever be desired. | |
| 23 | + | |
| 24 | +foreach my $d ( | |
| 25 | + ['--qdf', 'qdf', 'qdf'], | |
| 26 | + ['--newline-before-endstream', 'newline', 'nl'], | |
| 27 | + ['--qdf --newline-before-endstream', 'newline and qdf', 'nl-qdf'], | |
| 28 | + ['--object-streams=generate --newline-before-endstream', | |
| 29 | + 'newline and object streams', 'nl-objstm'], | |
| 30 | + ) | |
| 31 | +{ | |
| 32 | + my ($flags, $description, $suffix) = @$d; | |
| 33 | + $td->runtest("newline before endstream: $description", | |
| 34 | + {$td->COMMAND => "qpdf --static-id --stream-data=preserve" . | |
| 35 | + " $flags streams-with-newlines.pdf a.pdf"}, | |
| 36 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 37 | + $td->NORMALIZE_NEWLINES); | |
| 38 | + $td->runtest("check output ($description)", | |
| 39 | + {$td->FILE => "a.pdf"}, | |
| 40 | + {$td->FILE => "newline-before-endstream-$suffix.pdf"}); | |
| 41 | + if ($flags =~ /qdf/) | |
| 42 | + { | |
| 43 | + $td->runtest("fix-qdf", | |
| 44 | + {$td->COMMAND => "fix-qdf a.pdf"}, | |
| 45 | + {$td->FILE => "a.pdf", $td->EXIT_STATUS => 0}); | |
| 46 | + } | |
| 47 | +} | |
| 48 | + | |
| 49 | +$td->runtest("newline before endstream (C)", | |
| 50 | + {$td->COMMAND => | |
| 51 | + "qpdf-ctest 22 streams-with-newlines.pdf '' a.pdf"}, | |
| 52 | + {$td->STRING => "C test 22 done\n", $td->EXIT_STATUS => 0}, | |
| 53 | + $td->NORMALIZE_NEWLINES); | |
| 54 | +$td->runtest("check output", | |
| 55 | + {$td->FILE => "a.pdf"}, | |
| 56 | + {$td->FILE => "newline-before-endstream-nl.pdf"}); | |
| 57 | + | |
| 58 | +cleanup(); | |
| 59 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/numbers_and_strings.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('numbers_and_strings'); | |
| 16 | + | |
| 17 | +my $n_tests = 3; | |
| 18 | + | |
| 19 | +foreach (my $i = 1; $i <= 3; ++$i) | |
| 20 | +{ | |
| 21 | + $td->runtest("numbers and strings", | |
| 22 | + {$td->COMMAND => "test_driver 5 numeric-and-string-$i.pdf"}, | |
| 23 | + {$td->FILE => "numeric-and-string-$i.out", | |
| 24 | + $td->EXIT_STATUS => 0}, | |
| 25 | + $td->NORMALIZE_NEWLINES); | |
| 26 | +} | |
| 27 | + | |
| 28 | +cleanup(); | |
| 29 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/object_copying.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('object_copying'); | |
| 16 | + | |
| 17 | +my $n_tests = 9; | |
| 18 | + | |
| 19 | +$td->runtest("shallow copy an array", | |
| 20 | + {$td->COMMAND => "test_driver 20 shallow_array.pdf"}, | |
| 21 | + {$td->STRING => "test 20 done\n", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("check output", | |
| 24 | + {$td->FILE => "a.pdf"}, | |
| 25 | + {$td->FILE => "shallow_array-out.pdf"}); | |
| 26 | +$td->runtest("shallow copy a stream", | |
| 27 | + {$td->COMMAND => "test_driver 21 shallow_array.pdf"}, | |
| 28 | + {$td->FILE => "shallow_stream.out", $td->EXIT_STATUS => 2}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | +$td->runtest("warn for unknown key in Pages", | |
| 31 | + {$td->COMMAND => "test_driver 23 lin-special.pdf"}, | |
| 32 | + {$td->FILE => "pages-warning.out", $td->EXIT_STATUS => 0}, | |
| 33 | + $td->NORMALIZE_NEWLINES); | |
| 34 | +$td->runtest("reserved objects", | |
| 35 | + {$td->COMMAND => "test_driver 24 minimal.pdf"}, | |
| 36 | + {$td->FILE => "reserved-objects.out", $td->EXIT_STATUS => 0}, | |
| 37 | + $td->NORMALIZE_NEWLINES); | |
| 38 | +$td->runtest("check output", | |
| 39 | + {$td->FILE => "a.pdf"}, | |
| 40 | + {$td->FILE => "reserved-objects.pdf"}); | |
| 41 | +$td->runtest("detect foreign object in write", | |
| 42 | + {$td->COMMAND => "test_driver 29" . | |
| 43 | + " copy-foreign-objects-in.pdf minimal.pdf"}, | |
| 44 | + {$td->FILE => "foreign-in-write.out", $td->EXIT_STATUS => 0}, | |
| 45 | + $td->NORMALIZE_NEWLINES); | |
| 46 | +$td->runtest("copy a stream", | |
| 47 | + {$td->COMMAND => "test_driver 79 minimal.pdf"}, | |
| 48 | + {$td->STRING => "test 79 done\n", $td->EXIT_STATUS => 0}, | |
| 49 | + $td->NORMALIZE_NEWLINES); | |
| 50 | +$td->runtest("check output", | |
| 51 | + {$td->FILE => "a.pdf"}, | |
| 52 | + {$td->FILE => "test79.pdf"}); | |
| 53 | + | |
| 54 | +cleanup(); | |
| 55 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/object_handle_api.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('object_handle_api'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("dictionary keys", | |
| 20 | + {$td->COMMAND => "test_driver 87 - -"}, | |
| 21 | + {$td->STRING => "test 87 done\n", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("fluent interfaces", | |
| 24 | + {$td->COMMAND => "test_driver 88 minimal.pdf -"}, | |
| 25 | + {$td->FILE => "test88.out", $td->EXIT_STATUS => 0}, | |
| 26 | + $td->NORMALIZE_NEWLINES); | |
| 27 | + | |
| 28 | +cleanup(); | |
| 29 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/object_stream.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | +use Digest::MD5; | |
| 6 | +use File::Copy; | |
| 7 | + | |
| 8 | +unshift(@INC, '.'); | |
| 9 | +require qpdf_test_helpers; | |
| 10 | + | |
| 11 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 12 | + | |
| 13 | +require TestDriver; | |
| 14 | + | |
| 15 | +cleanup(); | |
| 16 | + | |
| 17 | +my $td = new TestDriver('object_stream'); | |
| 18 | + | |
| 19 | +my $n_tests = 3 + (36 * 4) + (12 * 2); | |
| 20 | +my $n_compare_pdfs = 36; | |
| 21 | + | |
| 22 | +for (my $n = 16; $n <= 19; ++$n) | |
| 23 | +{ | |
| 24 | + my $in = "good$n.pdf"; | |
| 25 | + foreach my $flags ('-object-streams=disable', | |
| 26 | + '-object-streams=preserve', | |
| 27 | + '-object-streams=generate') | |
| 28 | + { | |
| 29 | + foreach my $qdf ('-qdf', '', '-allow-weak-crypto -encrypt "" x 128 --') | |
| 30 | + { | |
| 31 | + # 4 tests + 1 compare_pdfs * 36 cases | |
| 32 | + # 2 additional tests * 12 cases | |
| 33 | + $td->runtest("object stream mode", | |
| 34 | + {$td->COMMAND => | |
| 35 | + "qpdf --static-id $flags $qdf $in a.pdf"}, | |
| 36 | + {$td->STRING => "", | |
| 37 | + $td->EXIT_STATUS => 0}); | |
| 38 | + compare_pdfs($td, "good$n.pdf", "a.pdf"); | |
| 39 | + if ($qdf eq '-qdf') | |
| 40 | + { | |
| 41 | + $td->runtest("fix-qdf identity check", | |
| 42 | + {$td->COMMAND => "fix-qdf a.pdf >| b.pdf"}, | |
| 43 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 44 | + $td->runtest("compare files", | |
| 45 | + {$td->FILE => "a.pdf"}, | |
| 46 | + {$td->FILE => "b.pdf"}); | |
| 47 | + } | |
| 48 | + $td->runtest("convert to qdf", | |
| 49 | + {$td->COMMAND => | |
| 50 | + "qpdf --static-id --no-original-object-ids" . | |
| 51 | + " -qdf -decrypt" . | |
| 52 | + " -object-streams=disable $in a.qdf"}, | |
| 53 | + {$td->STRING => "", | |
| 54 | + $td->EXIT_STATUS => 0}); | |
| 55 | + $td->runtest("convert output to qdf", | |
| 56 | + {$td->COMMAND => | |
| 57 | + "qpdf --static-id --no-original-object-ids" . | |
| 58 | + " -qdf -object-streams=disable a.pdf b.qdf"}, | |
| 59 | + {$td->STRING => "", | |
| 60 | + $td->EXIT_STATUS => 0}); | |
| 61 | + $td->runtest("compare files", | |
| 62 | + {$td->FILE => "a.qdf"}, | |
| 63 | + {$td->FILE => "b.qdf"}); | |
| 64 | + } | |
| 65 | + } | |
| 66 | + flush_tiff_cache(); | |
| 67 | +} | |
| 68 | + | |
| 69 | +# The file override-compressed-object.pdf contains an object stream | |
| 70 | +# with four strings in it. The file is then appended. The appended | |
| 71 | +# section overrides one of the four strings with a string in another | |
| 72 | +# object stream and another one in an uncompressed object. The other | |
| 73 | +# two strings are left alone. The test case exercises that all four | |
| 74 | +# objects have the correct value. | |
| 75 | +$td->runtest("overridden compressed objects", | |
| 76 | + {$td->COMMAND => "test_driver 38 override-compressed-object.pdf"}, | |
| 77 | + {$td->FILE => "override-compressed-object.out", | |
| 78 | + $td->EXIT_STATUS => 0}, | |
| 79 | + $td->NORMALIZE_NEWLINES); | |
| 80 | + | |
| 81 | +$td->runtest("generate object streams for gen > 0", | |
| 82 | + {$td->COMMAND => "qpdf --qdf --static-id" . | |
| 83 | + " --object-streams=generate gen1.pdf a.pdf"}, | |
| 84 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 85 | +$td->runtest("check file", | |
| 86 | + {$td->FILE => "a.pdf"}, | |
| 87 | + {$td->FILE => "gen1.qdf"}); | |
| 88 | + | |
| 89 | + | |
| 90 | +cleanup(); | |
| 91 | +$td->report(calc_ntests($n_tests, $n_compare_pdfs)); | ... | ... |
qpdf/qtest/outlines.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('outlines'); | |
| 16 | + | |
| 17 | +my @outline_files = ( | |
| 18 | + 'page-labels-and-outlines', | |
| 19 | + 'outlines-with-actions', | |
| 20 | + 'outlines-with-old-root-dests', | |
| 21 | + 'outlines-with-loop', | |
| 22 | + ); | |
| 23 | +my $n_tests = scalar(@outline_files); | |
| 24 | +foreach my $f (@outline_files) | |
| 25 | +{ | |
| 26 | + $td->runtest("outlines: $f", | |
| 27 | + {$td->COMMAND => "test_driver 49 $f.pdf"}, | |
| 28 | + {$td->FILE => "$f.out", $td->EXIT_STATUS => 0}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | +} | |
| 31 | + | |
| 32 | +cleanup(); | |
| 33 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/output_redirection.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('output_redirection'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("error/output redirection to null", | |
| 20 | + {$td->COMMAND => "test_driver 12 linearized-and-warnings.pdf"}, | |
| 21 | + {$td->FILE => "linearized-and-warnings-1.out", | |
| 22 | + $td->EXIT_STATUS => 0}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | + | |
| 25 | +$td->runtest("error/output redirection to strings", | |
| 26 | + {$td->COMMAND => "test_driver 13 linearized-and-warnings.pdf"}, | |
| 27 | + {$td->FILE => "linearized-and-warnings-2.out", | |
| 28 | + $td->EXIT_STATUS => 0}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | + | |
| 31 | +cleanup(); | |
| 32 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/overwrite_self.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | +use File::Copy; | |
| 6 | + | |
| 7 | +unshift(@INC, '.'); | |
| 8 | +require qpdf_test_helpers; | |
| 9 | + | |
| 10 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 11 | + | |
| 12 | +require TestDriver; | |
| 13 | + | |
| 14 | +cleanup(); | |
| 15 | + | |
| 16 | +my $td = new TestDriver('overwrite_self'); | |
| 17 | + | |
| 18 | +my $n_tests = 3; | |
| 19 | + | |
| 20 | +copy("minimal.pdf", "a.pdf"); | |
| 21 | +copy("minimal.pdf", "split-out.pdf"); | |
| 22 | +# Also tests @- for reading args from stdin | |
| 23 | +$td->runtest("don't overwrite self", | |
| 24 | + {$td->COMMAND => "(echo a.pdf; echo a.pdf) | qpdf \@-"}, | |
| 25 | + {$td->REGEXP => "input file and output file are the same.*", | |
| 26 | + $td->EXIT_STATUS => 2}); | |
| 27 | +$td->runtest("output is not really output for split", | |
| 28 | + {$td->COMMAND => "qpdf --split-pages split-out.pdf split-out.pdf"}, | |
| 29 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 30 | +$td->runtest("don't overwrite self (split)", | |
| 31 | + {$td->COMMAND => | |
| 32 | + "qpdf --split-pages split-out-1.pdf split-out.pdf"}, | |
| 33 | + {$td->REGEXP => | |
| 34 | + ".*split pages would overwrite.* split-out-1.pdf", | |
| 35 | + $td->EXIT_STATUS => 2}); | |
| 36 | + | |
| 37 | +cleanup(); | |
| 38 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/page_api.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('page_api'); | |
| 16 | + | |
| 17 | +my $n_tests = 11; | |
| 18 | + | |
| 19 | +$td->runtest("basic page API", | |
| 20 | + {$td->COMMAND => "test_driver 15 page_api_1.pdf"}, | |
| 21 | + {$td->STRING => "test 15 done\n", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("check output", | |
| 24 | + {$td->FILE => "a.pdf"}, | |
| 25 | + {$td->FILE => "page_api_1-out.pdf"}); | |
| 26 | +$td->runtest("manual page manipulation", | |
| 27 | + {$td->COMMAND => "test_driver 16 page_api_1.pdf"}, | |
| 28 | + {$td->STRING => "test 16 done\n", $td->EXIT_STATUS => 0}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | +$td->runtest("check output", | |
| 31 | + {$td->FILE => "a.pdf"}, | |
| 32 | + {$td->FILE => "page_api_1-out2.pdf"}); | |
| 33 | +$td->runtest("duplicate page", | |
| 34 | + {$td->COMMAND => "test_driver 17 page_api_2.pdf"}, | |
| 35 | + {$td->FILE => "page_api_2.out", $td->EXIT_STATUS => 0}, | |
| 36 | + $td->NORMALIZE_NEWLINES); | |
| 37 | +$td->runtest("delete and re-add a page", | |
| 38 | + {$td->COMMAND => "test_driver 18 page_api_1.pdf"}, | |
| 39 | + {$td->STRING => "test 18 done\n", $td->EXIT_STATUS => 0}, | |
| 40 | + $td->NORMALIZE_NEWLINES); | |
| 41 | +$td->runtest("check output", | |
| 42 | + {$td->FILE => "a.pdf"}, | |
| 43 | + {$td->FILE => "page_api_1-out3.pdf"}); | |
| 44 | +$td->runtest("duplicate page", | |
| 45 | + {$td->COMMAND => "test_driver 19 page_api_1.pdf"}, | |
| 46 | + {$td->FILE => "page_api_1.out", $td->EXIT_STATUS => 0}, | |
| 47 | + $td->NORMALIZE_NEWLINES); | |
| 48 | +$td->runtest("remove page we don't have", | |
| 49 | + {$td->COMMAND => "test_driver 22 page_api_1.pdf"}, | |
| 50 | + {$td->FILE => "page_api_1.out2", $td->EXIT_STATUS => 2}, | |
| 51 | + $td->NORMALIZE_NEWLINES); | |
| 52 | +$td->runtest("flatten rotation", | |
| 53 | + {$td->COMMAND => "qpdf --static-id --qdf". | |
| 54 | + " --no-original-object-ids" . | |
| 55 | + " --flatten-rotation boxes.pdf a.pdf"}, | |
| 56 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 57 | + $td->NORMALIZE_NEWLINES); | |
| 58 | +$td->runtest("check output", | |
| 59 | + {$td->FILE => "a.pdf"}, | |
| 60 | + {$td->FILE => "boxes-flattened.pdf"}); | |
| 61 | +cleanup(); | |
| 62 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/page_errors.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('page_errors'); | |
| 16 | + | |
| 17 | +my $n_tests = 5; | |
| 18 | + | |
| 19 | +$td->runtest("handle page no with contents", | |
| 20 | + {$td->COMMAND => "qpdf --show-pages page-no-content.pdf"}, | |
| 21 | + {$td->FILE => "page-no-content.out", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("check no type key for page nodes", | |
| 24 | + {$td->COMMAND => "qpdf --check no-pages-types.pdf"}, | |
| 25 | + {$td->FILE => "no-pages-types.out", $td->EXIT_STATUS => 3}, | |
| 26 | + $td->NORMALIZE_NEWLINES); | |
| 27 | +$td->runtest("no type key for page nodes", | |
| 28 | + {$td->COMMAND => "qpdf --static-id --split-pages no-pages-types.pdf a-split-out.pdf"}, | |
| 29 | + {$td->FILE => "no-pages-types-fix.out", $td->EXIT_STATUS => 3}, | |
| 30 | + $td->NORMALIZE_NEWLINES); | |
| 31 | +$td->runtest("check output", | |
| 32 | + {$td->FILE => "a-split-out-1.pdf"}, | |
| 33 | + {$td->FILE => "no-pages-types-fixed.pdf"}); | |
| 34 | +$td->runtest("detect loops in pages structure", | |
| 35 | + {$td->COMMAND => "qpdf --check pages-loop.pdf"}, | |
| 36 | + {$td->FILE => "pages-loop.out", $td->EXIT_STATUS => 2}, | |
| 37 | + $td->NORMALIZE_NEWLINES); | |
| 38 | + | |
| 39 | +cleanup(); | |
| 40 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/page_labels.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('page_labels'); | |
| 16 | + | |
| 17 | +my $n_tests = 3; | |
| 18 | + | |
| 19 | +$td->runtest("complex page labels", | |
| 20 | + {$td->COMMAND => "test_driver 47 page-labels-num-tree.pdf"}, | |
| 21 | + {$td->FILE => "page-labels-num-tree.out", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("no zero entry for page labels", | |
| 24 | + {$td->COMMAND => "test_driver 47 page-labels-no-zero.pdf"}, | |
| 25 | + {$td->FILE => "page-labels-no-zero.out", $td->EXIT_STATUS => 0}, | |
| 26 | + $td->NORMALIZE_NEWLINES); | |
| 27 | +$td->runtest("no page labels", | |
| 28 | + {$td->COMMAND => "test_driver 47 minimal.pdf"}, | |
| 29 | + {$td->FILE => "no-page-labels.out", $td->EXIT_STATUS => 0}, | |
| 30 | + $td->NORMALIZE_NEWLINES); | |
| 31 | + | |
| 32 | +cleanup(); | |
| 33 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/page_without_contents.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('page_without_contents'); | |
| 16 | + | |
| 17 | +my $n_tests = 7; | |
| 18 | + | |
| 19 | +$td->runtest("check no contents", | |
| 20 | + {$td->COMMAND => "qpdf --check no-contents.pdf"}, | |
| 21 | + {$td->FILE => "no-contents-check.out", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | + | |
| 24 | +foreach my $arg ('--qdf', '--coalesce-contents', '') | |
| 25 | +{ | |
| 26 | + $td->runtest("convert no contents ($arg)", | |
| 27 | + {$td->COMMAND => | |
| 28 | + "qpdf $arg --static-id no-contents.pdf a.pdf"}, | |
| 29 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 30 | + | |
| 31 | + my $suf = $arg; | |
| 32 | + $suf =~ s/--//; | |
| 33 | + if ($suf eq '') | |
| 34 | + { | |
| 35 | + $suf = "none"; | |
| 36 | + } | |
| 37 | + $td->runtest("check output", | |
| 38 | + {$td->FILE => "a.pdf"}, | |
| 39 | + {$td->FILE => "no-contents-$suf.pdf"}); | |
| 40 | +} | |
| 41 | + | |
| 42 | +cleanup(); | |
| 43 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/pages_tree.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('pages_tree'); | |
| 16 | + | |
| 17 | +my $n_tests = 11; | |
| 18 | + | |
| 19 | +$td->runtest("linearize duplicated pages", | |
| 20 | + {$td->COMMAND => | |
| 21 | + "qpdf --static-id --linearize" . | |
| 22 | + " page_api_2.pdf a.pdf"}, | |
| 23 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 24 | + $td->NORMALIZE_NEWLINES); | |
| 25 | +$td->runtest("compare files", | |
| 26 | + {$td->FILE => "a.pdf"}, | |
| 27 | + {$td->FILE => "linearize-duplicate-page.pdf"}); | |
| 28 | +$td->runtest("extract duplicated pages", | |
| 29 | + {$td->COMMAND => | |
| 30 | + "qpdf --static-id page_api_2.pdf" . | |
| 31 | + " --pages . -- a.pdf"}, | |
| 32 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 33 | + $td->NORMALIZE_NEWLINES); | |
| 34 | +$td->runtest("compare files", | |
| 35 | + {$td->FILE => "a.pdf"}, | |
| 36 | + {$td->FILE => "extract-duplicate-page.pdf"}); | |
| 37 | +$td->runtest("direct pages", | |
| 38 | + {$td->COMMAND => | |
| 39 | + "qpdf --static-id direct-pages.pdf --pages . -- a.pdf"}, | |
| 40 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 41 | + $td->NORMALIZE_NEWLINES); | |
| 42 | +$td->runtest("check output", | |
| 43 | + {$td->FILE => "a.pdf"}, | |
| 44 | + {$td->FILE => "direct-pages-fixed.pdf"}); | |
| 45 | +$td->runtest("show direct pages", | |
| 46 | + {$td->COMMAND => | |
| 47 | + "qpdf --show-pages direct-pages.pdf"}, | |
| 48 | + {$td->FILE => "direct-pages.out", $td->EXIT_STATUS => 0}, | |
| 49 | + $td->NORMALIZE_NEWLINES); | |
| 50 | + | |
| 51 | +# Json mode for direct and duplicated pages illustrates that the | |
| 52 | +# "objects" section the original objects before correction when | |
| 53 | +# "pages" is not output but after correct when it is.# numbers. | |
| 54 | +foreach my $f (qw(page_api_2 direct-pages)) | |
| 55 | +{ | |
| 56 | + $td->runtest("json for $f (objects only)", | |
| 57 | + {$td->COMMAND => | |
| 58 | + "qpdf --json=latest $f.pdf" . | |
| 59 | + " --json-key=qpdf"}, | |
| 60 | + {$td->FILE => "$f-json-objects.out", $td->EXIT_STATUS => 0}, | |
| 61 | + $td->NORMALIZE_NEWLINES); | |
| 62 | + $td->runtest("json for $f (with pages)", | |
| 63 | + {$td->COMMAND => | |
| 64 | + "qpdf --json=latest $f.pdf" . | |
| 65 | + " --json-key=qpdf --json-key=pages"}, | |
| 66 | + {$td->FILE => "$f-json-pages.out", $td->EXIT_STATUS => 0}, | |
| 67 | + $td->NORMALIZE_NEWLINES); | |
| 68 | +} | |
| 69 | + | |
| 70 | +cleanup(); | |
| 71 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/parsed_offset.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('parsed_offset'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("parsed offset without object streams", | |
| 20 | + {$td->COMMAND => "test_parsedoffset minimal.pdf"}, | |
| 21 | + {$td->FILE => "minimal-parsedoffset.out", | |
| 22 | + $td->EXIT_STATUS => 0}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | + | |
| 25 | +$td->runtest("parsed offset with object streams", | |
| 26 | + {$td->COMMAND => "test_parsedoffset digitally-signed.pdf"}, | |
| 27 | + {$td->FILE => "digitally-signed-parsedoffset.out", | |
| 28 | + $td->EXIT_STATUS => 0}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | + | |
| 31 | +cleanup(); | |
| 32 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/parsing.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('parsing'); | |
| 16 | + | |
| 17 | +my $n_tests = 17; | |
| 18 | + | |
| 19 | +$td->runtest("parse objects from string", | |
| 20 | + {$td->COMMAND => "test_driver 31 minimal.pdf"}, # file not used | |
| 21 | + {$td->FILE => "parse-object.out", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("EOF terminating literal tokens", | |
| 24 | + {$td->COMMAND => "qpdf --check eof-terminates-literal.pdf"}, | |
| 25 | + {$td->FILE => "eof-terminates-literal.out", $td->EXIT_STATUS => 0}, | |
| 26 | + $td->NORMALIZE_NEWLINES); | |
| 27 | +$td->runtest("EOF reading token", | |
| 28 | + {$td->COMMAND => "qpdf --check eof-reading-token.pdf"}, | |
| 29 | + {$td->FILE => "eof-reading-token.out", $td->EXIT_STATUS => 3}, | |
| 30 | + $td->NORMALIZE_NEWLINES); | |
| 31 | +$td->runtest("extra header text", | |
| 32 | + {$td->COMMAND => "test_driver 32 minimal.pdf"}, | |
| 33 | + {$td->FILE => "test-32.out", $td->EXIT_STATUS => 0}, | |
| 34 | + $td->NORMALIZE_NEWLINES); | |
| 35 | +$td->runtest("check output", | |
| 36 | + {$td->FILE => "a.pdf"}, | |
| 37 | + {$td->FILE => "extra-header-no-newline.pdf"}); | |
| 38 | +$td->runtest("check output", | |
| 39 | + {$td->FILE => "b.pdf"}, | |
| 40 | + {$td->FILE => "extra-header-lin-no-newline.pdf"}); | |
| 41 | +$td->runtest("check output", | |
| 42 | + {$td->FILE => "c.pdf"}, | |
| 43 | + {$td->FILE => "extra-header-newline.pdf"}); | |
| 44 | +$td->runtest("check output", | |
| 45 | + {$td->FILE => "d.pdf"}, | |
| 46 | + {$td->FILE => "extra-header-lin-newline.pdf"}); | |
| 47 | + | |
| 48 | +# leading-junk also has a space instead of a newline after xref | |
| 49 | +$td->runtest("check file with leading junk", | |
| 50 | + {$td->COMMAND => "qpdf --check leading-junk.pdf"}, | |
| 51 | + {$td->FILE => "leading-junk.out", $td->EXIT_STATUS => 0}, | |
| 52 | + $td->NORMALIZE_NEWLINES); | |
| 53 | +$td->runtest("EOF inside inline image", | |
| 54 | + {$td->COMMAND => "test_driver 37 eof-in-inline-image.pdf"}, | |
| 55 | + {$td->FILE => "eof-in-inline-image.out", | |
| 56 | + $td->EXIT_STATUS => 0}, | |
| 57 | + $td->NORMALIZE_NEWLINES); | |
| 58 | +$td->runtest("tokenize content streams", | |
| 59 | + {$td->COMMAND => "test_driver 37 tokenize-content-streams.pdf"}, | |
| 60 | + {$td->FILE => "tokenize-content-streams.out", | |
| 61 | + $td->EXIT_STATUS => 0}, | |
| 62 | + $td->NORMALIZE_NEWLINES); | |
| 63 | +$td->runtest("terminate parsing", | |
| 64 | + {$td->COMMAND => "test_driver 37 terminate-parsing.pdf"}, | |
| 65 | + {$td->FILE => "terminate-parsing.out", | |
| 66 | + $td->EXIT_STATUS => 0}, | |
| 67 | + $td->NORMALIZE_NEWLINES); | |
| 68 | +$td->runtest("content stream errors", | |
| 69 | + {$td->COMMAND => "qpdf --check content-stream-errors.pdf"}, | |
| 70 | + {$td->FILE => "content-stream-errors.out", | |
| 71 | + $td->EXIT_STATUS => 3}, | |
| 72 | + $td->NORMALIZE_NEWLINES); | |
| 73 | + | |
| 74 | +$td->runtest("ensure arguments to R are direct", | |
| 75 | + {$td->COMMAND => "qpdf --check indirect-r-arg.pdf"}, | |
| 76 | + {$td->FILE => "indirect-r-arg.out", $td->EXIT_STATUS => 3}, | |
| 77 | + $td->NORMALIZE_NEWLINES); | |
| 78 | +$td->runtest("no trailing space in xref table", | |
| 79 | + {$td->COMMAND => "qpdf --check no-space-in-xref.pdf"}, | |
| 80 | + {$td->FILE => "no-space-in-xref.out", $td->EXIT_STATUS => 0}, | |
| 81 | + $td->NORMALIZE_NEWLINES); | |
| 82 | + | |
| 83 | +# An array is split across multiple content streams starting object | |
| 84 | +# 42. This was reported in github issue 73. The file is modified from | |
| 85 | +# that example. | |
| 86 | +$td->runtest("parse split content stream", | |
| 87 | + {$td->COMMAND => "qpdf --check split-content-stream.pdf"}, | |
| 88 | + {$td->FILE => "split-content-stream.out", $td->EXIT_STATUS => 0}, | |
| 89 | + $td->NORMALIZE_NEWLINES); | |
| 90 | +$td->runtest("split content stream errors", | |
| 91 | + {$td->COMMAND => "qpdf --check split-content-stream-errors.pdf"}, | |
| 92 | + {$td->FILE => "split-content-stream-errors.out", | |
| 93 | + $td->EXIT_STATUS => 2}, | |
| 94 | + $td->NORMALIZE_NEWLINES); | |
| 95 | + | |
| 96 | +cleanup(); | |
| 97 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/pclm.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('pclm'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("write as PCLm", | |
| 20 | + {$td->COMMAND => "test_driver 40 pclm-in.pdf a.pdf"}, | |
| 21 | + {$td->STRING => "test 40 done\n", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("check output", | |
| 24 | + {$td->FILE => "a.pdf"}, | |
| 25 | + {$td->FILE => "pclm-out.pdf"}); | |
| 26 | + | |
| 27 | +cleanup(); | |
| 28 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/positive_p.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('positive_p'); | |
| 16 | + | |
| 17 | +my $n_tests = 4; | |
| 18 | + | |
| 19 | +# Files have been seen where /P in the encryption dictionary was an | |
| 20 | +# unsigned rather than a signed integer. To create | |
| 21 | +# encrypted-positive-P.pdf, I temporarily modified QPDFWriter.cc to | |
| 22 | +# introduce this error. | |
| 23 | + | |
| 24 | +$td->runtest("decrypt positive P", | |
| 25 | + {$td->COMMAND => | |
| 26 | + "qpdf --decrypt --static-id encrypted-positive-P.pdf a.pdf"}, | |
| 27 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 28 | +$td->runtest("check output", | |
| 29 | + {$td->FILE => "a.pdf"}, | |
| 30 | + {$td->FILE => "decrypted-positive-P.pdf"}); | |
| 31 | +$td->runtest("copy encryption positive P", | |
| 32 | + {$td->COMMAND => | |
| 33 | + "qpdf --static-id --static-aes-iv" . | |
| 34 | + " encrypted-positive-P.pdf a.pdf"}, | |
| 35 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 36 | +$td->runtest("check output", | |
| 37 | + {$td->FILE => "a.pdf"}, | |
| 38 | + {$td->FILE => "copied-positive-P.pdf"}); | |
| 39 | + | |
| 40 | +cleanup(); | |
| 41 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/precheck_streams.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('precheck_streams'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("bad stream", | |
| 20 | + {$td->COMMAND => "qpdf --static-id bad-data.pdf a.pdf"}, | |
| 21 | + {$td->FILE => "bad-data.out", $td->EXIT_STATUS => 3}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("check output", | |
| 24 | + {$td->FILE => "a.pdf"}, | |
| 25 | + {$td->FILE => "bad-data-out.pdf"}); | |
| 26 | + | |
| 27 | +cleanup(); | |
| 28 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/preserve_unref.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('preserve_unref'); | |
| 16 | + | |
| 17 | +my $n_tests = 6; | |
| 18 | + | |
| 19 | +$td->runtest("drop unused objects", | |
| 20 | + {$td->COMMAND => "qpdf --static-id unreferenced-objects.pdf a.pdf"}, | |
| 21 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 22 | +$td->runtest("check output", | |
| 23 | + {$td->FILE => "a.pdf"}, | |
| 24 | + {$td->FILE => "unreferenced-dropped.pdf"}); | |
| 25 | +$td->runtest("keep unused objects", | |
| 26 | + {$td->COMMAND => "qpdf --static-id --preserve-unreferenced" . | |
| 27 | + " unreferenced-objects.pdf a.pdf"}, | |
| 28 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 29 | +$td->runtest("check output", | |
| 30 | + {$td->FILE => "a.pdf"}, | |
| 31 | + {$td->FILE => "unreferenced-preserved.pdf"}); | |
| 32 | +$td->runtest("keep unused objects (C)", | |
| 33 | + {$td->COMMAND => | |
| 34 | + "qpdf-ctest 21 unreferenced-objects.pdf '' a.pdf"}, | |
| 35 | + {$td->STRING => "C test 21 done\n", $td->EXIT_STATUS => 0}, | |
| 36 | + $td->NORMALIZE_NEWLINES); | |
| 37 | +$td->runtest("check output", | |
| 38 | + {$td->FILE => "a.pdf"}, | |
| 39 | + {$td->FILE => "unreferenced-preserved.pdf"}); | |
| 40 | +cleanup(); | |
| 41 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/progress_reporting.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('progress_reporting'); | |
| 16 | + | |
| 17 | +my $n_tests = 1; | |
| 18 | + | |
| 19 | +$td->runtest("progress report on small file", | |
| 20 | + {$td->COMMAND => "qpdf --progress minimal.pdf a.pdf", | |
| 21 | + $td->FILTER => "perl filter-progress.pl"}, | |
| 22 | + {$td->FILE => "small-progress.out", $td->EXIT_STATUS => 0}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | + | |
| 25 | +cleanup(); | |
| 26 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/qpdf.test deleted
Changes suppressed. Click to show
| 1 | -#!/usr/bin/env perl | |
| 2 | -require 5.008; | |
| 3 | -BEGIN { $^W = 1; } | |
| 4 | -use strict; | |
| 5 | -use Cwd; | |
| 6 | -use Digest::MD5; | |
| 7 | -use File::Basename; | |
| 8 | -use File::Copy; | |
| 9 | -use File::Compare; | |
| 10 | -use File::Spec; | |
| 11 | - | |
| 12 | -unshift(@INC, '../../libtests/qtest/arg_parser'); | |
| 13 | -require completion_helpers; | |
| 14 | - | |
| 15 | -chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 16 | - | |
| 17 | -require TestDriver; | |
| 18 | - | |
| 19 | -cleanup(); | |
| 20 | - | |
| 21 | -my $devNull = File::Spec->devnull(); | |
| 22 | -my $td = new TestDriver('qpdf'); | |
| 23 | - | |
| 24 | -my $compare_images = 0; | |
| 25 | -if ((exists $ENV{'QPDF_TEST_COMPARE_IMAGES'}) && | |
| 26 | - ($ENV{'QPDF_TEST_COMPARE_IMAGES'} eq '1')) | |
| 27 | -{ | |
| 28 | - $compare_images = 1; | |
| 29 | -} | |
| 30 | -my $large_file_test_path = $ENV{'QPDF_LARGE_FILE_TEST_PATH'} || undef; | |
| 31 | -if (defined($large_file_test_path)) | |
| 32 | -{ | |
| 33 | - $large_file_test_path = File::Spec->rel2abs($large_file_test_path); | |
| 34 | - $large_file_test_path =~ s!\\!/!g; | |
| 35 | -} | |
| 36 | - | |
| 37 | -# These variables are used to store the total number of tests in the | |
| 38 | -# test suite. NOTE: qtest's requirement to indicate the number of | |
| 39 | -# tests serves as a check that the test suite is operating properly. | |
| 40 | -# Do not calculate these values as a side effect of running the tests. | |
| 41 | -# That defeats the purpose. However, since this test suite consists | |
| 42 | -# of several separate series of tests, many of which iterate over | |
| 43 | -# static lists of things, we calculate the numbers as we go in terms | |
| 44 | -# of static values. | |
| 45 | - | |
| 46 | -# This should be set to the number of times we called compare_pdfs. | |
| 47 | -# This has to be kept separate because the number of test cases | |
| 48 | -# compare_pdfs generates depends on the value of $compare_images. | |
| 49 | -my $n_compare_pdfs = 0; | |
| 50 | - | |
| 51 | -# Each section of tests should increment this number by the number of | |
| 52 | -# tests they generate excluding calls to compare_pdfs, which are | |
| 53 | -# tracked separately by $n_compare_pdfs. | |
| 54 | -my $n_tests = 0; | |
| 55 | - | |
| 56 | -# Call show_ntests after each block of test cases. In show_ntests, | |
| 57 | -# you can turn on printing of the expected number of test cases. This | |
| 58 | -# is useful for tracking down problems in the number of test cases. | |
| 59 | - | |
| 60 | -show_ntests(); | |
| 61 | -# ---------- | |
| 62 | - | |
| 63 | -$n_compare_pdfs += 5; | |
| 64 | - | |
| 65 | -# Check compare_pdfs to make sure that it works properly. Each call | |
| 66 | -# to compare_pdfs is worth three test cases. | |
| 67 | -compare_pdfs("p1-a-p2-b.pdf", "p1-a-p2-b.pdf"); | |
| 68 | -compare_pdfs("p1-a.pdf", "p1-a.pdf"); | |
| 69 | -compare_pdfs("p1-a.pdf", "p1-b.pdf", 1); | |
| 70 | -compare_pdfs("p1-a.pdf", "p1-a-p2-b.pdf", 1); | |
| 71 | -compare_pdfs("p1-a-p2-a.pdf", "p1-a-p2-b.pdf", 1); | |
| 72 | -flush_tiff_cache(); | |
| 73 | - | |
| 74 | -show_ntests(); | |
| 75 | -# ---------- | |
| 76 | -$td->notify("--- Character Encoding ---"); | |
| 77 | -$n_tests += 4; | |
| 78 | - | |
| 79 | -$td->runtest("PDF doc encoding to Unicode", | |
| 80 | - {$td->COMMAND => "test_pdf_doc_encoding pdf-doc-to-utf8.in"}, | |
| 81 | - {$td->FILE => "pdf-doc-to-utf8.out", $td->EXIT_STATUS => 0}, | |
| 82 | - $td->NORMALIZE_NEWLINES); | |
| 83 | -$td->runtest("UTF-16 encoding", | |
| 84 | - {$td->COMMAND => "test_pdf_unicode unicode.in"}, | |
| 85 | - {$td->FILE => "unicode.out", $td->EXIT_STATUS => 0}, | |
| 86 | - $td->NORMALIZE_NEWLINES); | |
| 87 | -$td->runtest("UTF-16 encoding errors", | |
| 88 | - {$td->COMMAND => "test_pdf_unicode unicode-errors.in"}, | |
| 89 | - {$td->FILE => "unicode-errors.out", $td->EXIT_STATUS => 0}, | |
| 90 | - $td->NORMALIZE_NEWLINES); | |
| 91 | - | |
| 92 | -# UTF-16LE is not allowed by the PDF spec, but it seems that most | |
| 93 | -# readers accept it. | |
| 94 | -$td->runtest("UTF-16LE strings", | |
| 95 | - {$td->COMMAND => "qpdf --list-attachments --verbose utf16le.pdf"}, | |
| 96 | - {$td->FILE => "utf16le-attachments.out", $td->EXIT_STATUS => 0}, | |
| 97 | - $td->NORMALIZE_NEWLINES); | |
| 98 | - | |
| 99 | -# Tests to exercise QPDFArgParser belong in arg_parser.test in | |
| 100 | -# libtests. These tests are supposed to be specific to the qpdf cli. | |
| 101 | -# Since they were written prior to moving QPDFArgParser into the | |
| 102 | -# library, there are several tests here that also exercise | |
| 103 | -# QPDFArgParser logic. | |
| 104 | -my @completion_tests = ( | |
| 105 | - ['', 0, 'bad-input-1'], | |
| 106 | - ['', 1, 'bad-input-2'], | |
| 107 | - ['', 2, 'bad-input-3'], | |
| 108 | - ['qpdf', 2, 'bad-input-4'], | |
| 109 | - ['qpdf ', undef, 'top'], | |
| 110 | - ['qpdf -', undef, 'top-arg'], | |
| 111 | - ['qpdf --enc', undef, 'enc'], | |
| 112 | - ['qpdf --encrypt ', undef, 'encrypt'], | |
| 113 | - ['qpdf --encrypt u ', undef, 'encrypt-u'], | |
| 114 | - ['qpdf --encrypt u o ', undef, 'encrypt-u-o'], | |
| 115 | - ['qpdf @encrypt-u o ', undef, 'encrypt-u-o'], | |
| 116 | - ['qpdf --encrypt u o 40 --', undef, 'encrypt-40'], | |
| 117 | - ['qpdf --encrypt u o 128 --', undef, 'encrypt-128'], | |
| 118 | - ['qpdf --encrypt u o 256 --', undef, 'encrypt-256'], | |
| 119 | - ['qpdf --encrypt u o bad --', undef, 'encrypt-bad'], | |
| 120 | - ['qpdf --split-pag', undef, 'split'], | |
| 121 | - ['qpdf --decode-l', undef, 'decode-l'], | |
| 122 | - ['qpdf --decode-lzzz', 15, 'decode-l'], | |
| 123 | - ['qpdf --decode-level=', undef, 'decode-level'], | |
| 124 | - ['qpdf --decode-level=g', undef, 'decode-level-g'], | |
| 125 | - ['qpdf --check -', undef, 'later-arg'], | |
| 126 | - ['qpdf infile outfile oops --ch', undef, 'usage-empty'], | |
| 127 | - ['qpdf --encrypt \'user " password\' ', undef, 'quoting'], | |
| 128 | - ['qpdf --encrypt \'user password\' ', undef, 'quoting'], | |
| 129 | - ['qpdf --encrypt "user password" ', undef, 'quoting'], | |
| 130 | - ['qpdf --encrypt "user pass\'word" ', undef, 'quoting'], | |
| 131 | - ['qpdf --encrypt user\ password ', undef, 'quoting'], | |
| 132 | - ); | |
| 133 | -$n_tests += 2 * scalar(@completion_tests); | |
| 134 | -my $completion_filter = | |
| 135 | - "perl ../../../libtests/qtest/arg_parser/filter-completion.pl"; | |
| 136 | -foreach my $c (@completion_tests) | |
| 137 | -{ | |
| 138 | - my ($cmd, $point, $description) = @$c; | |
| 139 | - my $out = "completion-$description.out"; | |
| 140 | - my $zout = "completion-$description-zsh.out"; | |
| 141 | - if (! -f $zout) | |
| 142 | - { | |
| 143 | - $zout = $out; | |
| 144 | - } | |
| 145 | - $td->runtest("bash completion: $description", | |
| 146 | - {$td->COMMAND => [@{bash_completion("qpdf", $cmd, $point)}], | |
| 147 | - $td->FILTER => "$completion_filter $out"}, | |
| 148 | - {$td->FILE => "$out", $td->EXIT_STATUS => 0}, | |
| 149 | - $td->NORMALIZE_NEWLINES); | |
| 150 | - $td->runtest("zsh completion: $description", | |
| 151 | - {$td->COMMAND => [@{zsh_completion("qpdf", $cmd, $point)}], | |
| 152 | - $td->FILTER => "$completion_filter $zout"}, | |
| 153 | - {$td->FILE => "$zout", $td->EXIT_STATUS => 0}, | |
| 154 | - $td->NORMALIZE_NEWLINES); | |
| 155 | -} | |
| 156 | - | |
| 157 | -show_ntests(); | |
| 158 | -# ---------- | |
| 159 | -$td->notify("--- Argument Parsing ---"); | |
| 160 | -$n_tests += 13; | |
| 161 | - | |
| 162 | -$td->runtest("required argument", | |
| 163 | - {$td->COMMAND => "qpdf --password minimal.pdf"}, | |
| 164 | - {$td->REGEXP => "must be given as --password=pass", | |
| 165 | - $td->EXIT_STATUS => 2}, | |
| 166 | - $td->NORMALIZE_NEWLINES); | |
| 167 | -$td->runtest("required argument with choices", | |
| 168 | - {$td->COMMAND => "qpdf --decode-level minimal.pdf"}, | |
| 169 | - {$td->REGEXP => "must be given as --decode-level=\\{.*all.*\\}", | |
| 170 | - $td->EXIT_STATUS => 2}, | |
| 171 | - $td->NORMALIZE_NEWLINES); | |
| 172 | -$td->runtest("required argument with choices", | |
| 173 | - {$td->COMMAND => "qpdf --decode-level minimal.pdf"}, | |
| 174 | - {$td->REGEXP => "must be given as --decode-level=\\{.*all.*\\}", | |
| 175 | - $td->EXIT_STATUS => 2}, | |
| 176 | - $td->NORMALIZE_NEWLINES); | |
| 177 | -copy("minimal.pdf", '@file.pdf'); | |
| 178 | -$td->runtest("\@file exists and file doesn't", | |
| 179 | - {$td->COMMAND => "qpdf --check \@file.pdf"}, | |
| 180 | - {$td->FILE => "check-at-file.out", $td->EXIT_STATUS => 0}, | |
| 181 | - $td->NORMALIZE_NEWLINES); | |
| 182 | -$td->runtest("missing underlay filename", | |
| 183 | - {$td->COMMAND => "qpdf --underlay --"}, | |
| 184 | - {$td->REGEXP => ".*underlay file not specified.*", | |
| 185 | - $td->EXIT_STATUS => 2}, | |
| 186 | - $td->NORMALIZE_NEWLINES); | |
| 187 | -$td->runtest("extra overlay filename", | |
| 188 | - {$td->COMMAND => "qpdf --overlay x x --"}, | |
| 189 | - {$td->REGEXP => ".*overlay file already specified.*", | |
| 190 | - $td->EXIT_STATUS => 2}, | |
| 191 | - $td->NORMALIZE_NEWLINES); | |
| 192 | -$td->runtest("multiple pages options", | |
| 193 | - {$td->COMMAND => "qpdf --pages . --password=x -- --pages . --"}, | |
| 194 | - {$td->REGEXP => ".*--pages may only be specified one time.*", | |
| 195 | - $td->EXIT_STATUS => 2}, | |
| 196 | - $td->NORMALIZE_NEWLINES); | |
| 197 | -$td->runtest("bad numeric range detects unclosed --pages", | |
| 198 | - {$td->COMMAND => "qpdf --pages . --pages . --"}, | |
| 199 | - {$td->REGEXP => ".*pages options must be terminated with --.*", | |
| 200 | - $td->EXIT_STATUS => 2}, | |
| 201 | - $td->NORMALIZE_NEWLINES); | |
| 202 | -$td->runtest("bad file detected as unclosed --pages", | |
| 203 | - {$td->COMMAND => "qpdf --pages . 1 --xyz out"}, | |
| 204 | - {$td->REGEXP => ".*pages options must be terminated with --.*", | |
| 205 | - $td->EXIT_STATUS => 2}, | |
| 206 | - $td->NORMALIZE_NEWLINES); | |
| 207 | -$td->runtest("misplaced pages password 1", | |
| 208 | - {$td->COMMAND => "qpdf --pages . 1 --password=z --"}, | |
| 209 | - {$td->REGEXP => ".*password must immediately follow a file name.*", | |
| 210 | - $td->EXIT_STATUS => 2}, | |
| 211 | - $td->NORMALIZE_NEWLINES); | |
| 212 | -$td->runtest("misplaced pages password 2", | |
| 213 | - {$td->COMMAND => "qpdf --pages --password=z . 1 --"}, | |
| 214 | - {$td->REGEXP => ".*password must immediately follow a file name.*", | |
| 215 | - $td->EXIT_STATUS => 2}, | |
| 216 | - $td->NORMALIZE_NEWLINES); | |
| 217 | -$td->runtest("duplicated pages password", | |
| 218 | - {$td->COMMAND => "qpdf --pages . --password=z --password=z --"}, | |
| 219 | - {$td->REGEXP => ".*password already specified.*", | |
| 220 | - $td->EXIT_STATUS => 2}, | |
| 221 | - $td->NORMALIZE_NEWLINES); | |
| 222 | -# Ignoring -- at the top level was never intended but turned out to | |
| 223 | -# have been there for a long time so that people relied on it. It is | |
| 224 | -# intentionally not documented. | |
| 225 | -$td->runtest("ignore -- at top level", | |
| 226 | - {$td->COMMAND => "qpdf -- --check -- minimal.pdf --"}, | |
| 227 | - {$td->REGEXP => ".*No syntax or stream encoding errors found.*", | |
| 228 | - $td->EXIT_STATUS => 0}, | |
| 229 | - $td->NORMALIZE_NEWLINES); | |
| 230 | - | |
| 231 | -show_ntests(); | |
| 232 | -# ---------- | |
| 233 | -$td->notify("--- Unicode Filenames ---"); | |
| 234 | -$n_tests += 3; | |
| 235 | - | |
| 236 | -$td->runtest("create unicode filenames", | |
| 237 | - {$td->COMMAND => "test_unicode_filenames"}, | |
| 238 | - {$td->STRING => "created Unicode filenames\n", | |
| 239 | - $td->EXIT_STATUS => 0}, | |
| 240 | - $td->NORMALIZE_NEWLINES); | |
| 241 | - | |
| 242 | -foreach my $d (['auto-รผ', 1], ['auto-รถฯ', 2]) | |
| 243 | -{ | |
| 244 | - my ($u, $n) = @$d; | |
| 245 | - $td->runtest("unicode filename $u", | |
| 246 | - {$td->COMMAND => "qpdf --check $u.pdf"}, | |
| 247 | - {$td->FILE => "check-unicode-filename-$n.out", | |
| 248 | - $td->EXIT_STATUS => 0}, | |
| 249 | - $td->NORMALIZE_NEWLINES); | |
| 250 | -} | |
| 251 | - | |
| 252 | -show_ntests(); | |
| 253 | -# ---------- | |
| 254 | -$td->notify("--- Windows shell globbing ---"); | |
| 255 | - | |
| 256 | -$td->runtest("shell wildcard expansion", | |
| 257 | - {$td->COMMAND => "test_shell_glob 'good*.pdf'"}, | |
| 258 | - {$td->STRING => "PASSED\n", $td->EXIT_STATUS => 0}, | |
| 259 | - $td->NORMALIZE_NEWLINES); | |
| 260 | - | |
| 261 | -$n_tests += 1; | |
| 262 | - | |
| 263 | -show_ntests(); | |
| 264 | -# ---------- | |
| 265 | -$td->notify("--- Replace Input ---"); | |
| 266 | -$n_tests += 8; | |
| 267 | - | |
| 268 | -# Use Unicode file names to test replace input so we can be sure it | |
| 269 | -# works for that case. | |
| 270 | -$td->runtest("create unicode filenames", | |
| 271 | - {$td->COMMAND => "test_unicode_filenames"}, | |
| 272 | - {$td->STRING => "created Unicode filenames\n", | |
| 273 | - $td->EXIT_STATUS => 0}, | |
| 274 | - $td->NORMALIZE_NEWLINES); | |
| 275 | - | |
| 276 | -foreach my $d (['auto-รผ', 1], ['auto-รถฯ', 2]) | |
| 277 | -{ | |
| 278 | - my ($u, $n) = @$d; | |
| 279 | - $td->runtest("replace input $u", | |
| 280 | - {$td->COMMAND => "qpdf --deterministic-id" . | |
| 281 | - " --object-streams=generate --replace-input ./$u.pdf"}, | |
| 282 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 283 | - $td->NORMALIZE_NEWLINES); | |
| 284 | - $td->runtest("check output ($u)", | |
| 285 | - {$td->FILE => "$u.pdf"}, | |
| 286 | - {$td->FILE => "replace-input.pdf"}, | |
| 287 | - $td->NORMALIZE_NEWLINES); | |
| 288 | -} | |
| 289 | - | |
| 290 | -system("cp xref-with-short-size.pdf auto-warn.pdf") == 0 or die; | |
| 291 | -$td->runtest("replace input with warnings", | |
| 292 | - {$td->COMMAND => | |
| 293 | - "qpdf --deterministic-id --replace-input ./auto-warn.pdf"}, | |
| 294 | - {$td->FILE => "replace-warn.out", $td->EXIT_STATUS => 3}, | |
| 295 | - $td->NORMALIZE_NEWLINES); | |
| 296 | - | |
| 297 | -$td->runtest("check output", | |
| 298 | - {$td->FILE => "auto-warn.pdf"}, | |
| 299 | - {$td->FILE => "warn-replace.pdf"}); | |
| 300 | -$td->runtest("check orig output", | |
| 301 | - {$td->FILE => "auto-warn.pdf.~qpdf-orig"}, | |
| 302 | - {$td->FILE => "xref-with-short-size.pdf"}); | |
| 303 | - | |
| 304 | -show_ntests(); | |
| 305 | -# ---------- | |
| 306 | -$td->notify("--- Final Version ---"); | |
| 307 | -$n_tests += 1; | |
| 308 | - | |
| 309 | -$td->runtest("check final version", | |
| 310 | - {$td->COMMAND => "test_driver 54 minimal.pdf"}, | |
| 311 | - {$td->STRING => "test 54 done\n", $td->EXIT_STATUS => 0}, | |
| 312 | - $td->NORMALIZE_NEWLINES); | |
| 313 | - | |
| 314 | -show_ntests(); | |
| 315 | -# ---------- | |
| 316 | -$td->notify("--- Exceptions ---"); | |
| 317 | -$n_tests += 2; | |
| 318 | - | |
| 319 | -$td->runtest("check exception handling", | |
| 320 | - {$td->COMMAND => "test_driver 61 -"}, | |
| 321 | - {$td->FILE => "exceptions.out", $td->EXIT_STATUS => 0}, | |
| 322 | - $td->NORMALIZE_NEWLINES); | |
| 323 | -$td->runtest("check certain exception types", | |
| 324 | - {$td->COMMAND => "test_driver 81 -"}, | |
| 325 | - {$td->STRING => "test 81 done\n", $td->EXIT_STATUS => 0}, | |
| 326 | - $td->NORMALIZE_NEWLINES); | |
| 327 | - | |
| 328 | -show_ntests(); | |
| 329 | -# ---------- | |
| 330 | -$td->notify("--- Check encryption/password ---"); | |
| 331 | -my @check_encryption_password = ( | |
| 332 | - # file, password, is-encrypted, requires-password | |
| 333 | - ["minimal.pdf", "", 2, 2], | |
| 334 | - ["20-pages.pdf", "", 0, 0], | |
| 335 | - ["20-pages.pdf", "user", 0, 3], | |
| 336 | - ); | |
| 337 | -$n_tests += 3 * scalar(@check_encryption_password); | |
| 338 | -foreach my $d (@check_encryption_password) | |
| 339 | -{ | |
| 340 | - my ($file, $pass, $is_encrypted, $requires_password) = @$d; | |
| 341 | - $td->runtest("is encrypted ($file, pass=$pass)", | |
| 342 | - {$td->COMMAND => "qpdf --is-encrypted --password=$pass $file"}, | |
| 343 | - {$td->STRING => "", $td->EXIT_STATUS => $is_encrypted}); | |
| 344 | - $td->runtest("requires password ($file, pass=$pass)", | |
| 345 | - {$td->COMMAND => "qpdf --requires-password" . | |
| 346 | - " --password=$pass $file"}, | |
| 347 | - {$td->STRING => "", $td->EXIT_STATUS => $requires_password}); | |
| 348 | -} | |
| 349 | - | |
| 350 | -# Exercise reading password from file | |
| 351 | -open(F, ">args") or die; | |
| 352 | -print F "user\n"; | |
| 353 | -close(F); | |
| 354 | -$td->runtest("password from file)", | |
| 355 | - {$td->COMMAND => "qpdf --check --password-file=args 20-pages.pdf"}, | |
| 356 | - {$td->FILE => "20-pages-check.out", $td->EXIT_STATUS => 0}, | |
| 357 | - $td->NORMALIZE_NEWLINES); | |
| 358 | -open(F, ">>args") or die; | |
| 359 | -print F "ignored\n"; | |
| 360 | -close(F); | |
| 361 | -$td->runtest("ignore extra args from file)", | |
| 362 | - {$td->COMMAND => "qpdf --check --password-file=args 20-pages.pdf"}, | |
| 363 | - {$td->FILE => "20-pages-check-password-warning.out", | |
| 364 | - $td->EXIT_STATUS => 0}, | |
| 365 | - $td->NORMALIZE_NEWLINES); | |
| 366 | -unlink "args"; | |
| 367 | -$td->runtest("password from stdin)", | |
| 368 | - {$td->COMMAND => "echo user |" . | |
| 369 | - " qpdf --check --password-file=- 20-pages.pdf"}, | |
| 370 | - {$td->FILE => "20-pages-check.out", $td->EXIT_STATUS => 0}, | |
| 371 | - $td->NORMALIZE_NEWLINES); | |
| 372 | - | |
| 373 | -show_ntests(); | |
| 374 | -# ---------- | |
| 375 | -$td->notify("--- Dangling Refs ---"); | |
| 376 | -my @dangling = (qw(minimal dangling-refs)); | |
| 377 | -$n_tests += 2 * scalar(@dangling); | |
| 378 | - | |
| 379 | -foreach my $f (@dangling) | |
| 380 | -{ | |
| 381 | - $td->runtest("dangling refs: $f", | |
| 382 | - {$td->COMMAND => "test_driver 53 $f.pdf"}, | |
| 383 | - {$td->FILE => "$f-dangling.out", $td->EXIT_STATUS => 0}, | |
| 384 | - $td->NORMALIZE_NEWLINES); | |
| 385 | - $td->runtest("check output", | |
| 386 | - {$td->FILE => "a.pdf"}, | |
| 387 | - {$td->FILE => "$f-dangling-out.pdf"}); | |
| 388 | -} | |
| 389 | -show_ntests(); | |
| 390 | -# ---------- | |
| 391 | -$td->notify("--- QPDFJob Tests ---"); | |
| 392 | - | |
| 393 | -open(F, ">auto-txt") or die; | |
| 394 | -print F "from file"; | |
| 395 | -close(F); | |
| 396 | - | |
| 397 | -my @bad_json = ( | |
| 398 | - "bare-option-false", | |
| 399 | - "choice-mismatch", | |
| 400 | - "encrypt-duplicate-key-length", | |
| 401 | - "encrypt-missing-password", | |
| 402 | - "encrypt-no-key-length", | |
| 403 | - "pages-no-file", | |
| 404 | - "schema-error", | |
| 405 | - "json-error" | |
| 406 | - ); | |
| 407 | -my @good_json = ( | |
| 408 | - "choice-match", | |
| 409 | - "input-file-password", | |
| 410 | - "empty-input", | |
| 411 | - "replace-input", | |
| 412 | - "encrypt-40", | |
| 413 | - "encrypt-128", | |
| 414 | - "encrypt-256-with-restrictions", | |
| 415 | - "add-attachments", | |
| 416 | - "copy-attachments", | |
| 417 | - "underlay-overlay", | |
| 418 | - "underlay-overlay-password", | |
| 419 | - "misc-options", | |
| 420 | - ); | |
| 421 | -$n_tests += 10 + scalar(@bad_json) + (2 * scalar(@good_json)); | |
| 422 | - | |
| 423 | - | |
| 424 | -foreach my $i (@bad_json) | |
| 425 | -{ | |
| 426 | - $td->runtest("QPDFJob bad json: $i", | |
| 427 | - {$td->COMMAND => "qpdf --job-json-file=bad-json-$i.json"}, | |
| 428 | - {$td->FILE => "bad-$i-json.out", $td->EXIT_STATUS => 2}, | |
| 429 | - $td->NORMALIZE_NEWLINES); | |
| 430 | -} | |
| 431 | - | |
| 432 | -foreach my $i (@good_json) | |
| 433 | -{ | |
| 434 | - if ($i eq 'replace-input') | |
| 435 | - { | |
| 436 | - copy("minimal.pdf", 'a.pdf'); | |
| 437 | - } | |
| 438 | - $td->runtest("QPDFJob good json: $i", | |
| 439 | - {$td->COMMAND => "qpdf --job-json-file=job-json-$i.json"}, | |
| 440 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 441 | - $td->NORMALIZE_NEWLINES); | |
| 442 | - if ($i =~ m/encrypt-256/) | |
| 443 | - { | |
| 444 | - $td->runtest("check encryption $i", | |
| 445 | - {$td->COMMAND => | |
| 446 | - "qpdf a.pdf --password=u" . | |
| 447 | - " --job-json-file=job-show-encryption.json"}, | |
| 448 | - {$td->FILE => "job-json-$i.out", $td->EXIT_STATUS => 0}, | |
| 449 | - $td->NORMALIZE_NEWLINES); | |
| 450 | - } | |
| 451 | - else | |
| 452 | - { | |
| 453 | - $td->runtest("check good json $i output", | |
| 454 | - {$td->FILE => "a.pdf"}, | |
| 455 | - {$td->FILE => "job-json-$i.pdf"}); | |
| 456 | - } | |
| 457 | -} | |
| 458 | - | |
| 459 | - | |
| 460 | -$td->runtest("QPDFJob json partial", | |
| 461 | - {$td->COMMAND => "test_driver 83 - job-partial.json"}, | |
| 462 | - {$td->FILE => "job-partial-json.out", $td->EXIT_STATUS => 0}, | |
| 463 | - $td->NORMALIZE_NEWLINES); | |
| 464 | -$td->runtest("QPDFJob API", | |
| 465 | - {$td->COMMAND => "test_driver 84 -"}, | |
| 466 | - {$td->FILE => "job-api.out", $td->EXIT_STATUS => 0}, | |
| 467 | - $td->NORMALIZE_NEWLINES); | |
| 468 | -$td->runtest("check output", | |
| 469 | - {$td->FILE => "a.pdf"}, | |
| 470 | - {$td->FILE => "test84.pdf"}); | |
| 471 | -$td->runtest("json output from job", | |
| 472 | - {$td->COMMAND => "qpdf --job-json-file=job-json-output.json"}, | |
| 473 | - {$td->FILE => "job-json-output.out.json", $td->EXIT_STATUS => 0}, | |
| 474 | - $td->NORMALIZE_NEWLINES); | |
| 475 | - | |
| 476 | -$td->runtest("C job API", | |
| 477 | - {$td->COMMAND => "qpdfjob-ctest"}, | |
| 478 | - {$td->FILE => "qpdfjob-ctest.out", $td->EXIT_STATUS => 0}, | |
| 479 | - $td->NORMALIZE_NEWLINES); | |
| 480 | -foreach my $i (['a.pdf', 1], ['b.pdf', 2], ['c.pdf', 3]) | |
| 481 | -{ | |
| 482 | - $td->runtest("check output", | |
| 483 | - {$td->FILE => $i->[0]}, | |
| 484 | - {$td->FILE => "qpdfjob-ctest$i->[1].pdf"}); | |
| 485 | -} | |
| 486 | -my $wide_out = `qpdfjob-ctest wide`; | |
| 487 | -$td->runtest("qpdfjob-ctest wide", | |
| 488 | - {$td->STRING => "$?: $wide_out"}, | |
| 489 | - {$td->REGEXP => "0: (wide test passed|skipped wide)\n"}, | |
| 490 | - $td->NORMALIZE_NEWLINES); | |
| 491 | -if ($wide_out =~ m/skipped/) | |
| 492 | -{ | |
| 493 | - $td->runtest("skipped wide", | |
| 494 | - {$td->STRING => "yes"}, | |
| 495 | - {$td->STRING => "yes"}); | |
| 496 | -} | |
| 497 | -else | |
| 498 | -{ | |
| 499 | - $td->runtest("check output", | |
| 500 | - {$td->FILE => "a.pdf"}, | |
| 501 | - {$td->FILE => "qpdfjob-ctest-wide.pdf"}); | |
| 502 | -} | |
| 503 | - | |
| 504 | -show_ntests(); | |
| 505 | -# ---------- | |
| 506 | -$td->notify("--- Form Tests ---"); | |
| 507 | - | |
| 508 | -my @form_tests = ( | |
| 509 | - 'minimal', | |
| 510 | - 'form-empty-from-odt', | |
| 511 | - 'form-mod1', | |
| 512 | - # Atril (MATE Document Viewer) 1.20.1 dumps appearance streams | |
| 513 | - # when modifying form fields, leaving /NeedAppearances true. | |
| 514 | - 'form-filled-with-atril', | |
| 515 | - 'form-bad-fields-array', | |
| 516 | - 'form-errors', | |
| 517 | - 'form-document-defaults', | |
| 518 | - ); | |
| 519 | - | |
| 520 | -$n_tests += scalar(@form_tests) + 6; | |
| 521 | - | |
| 522 | -# Many of the form*.pdf files were created by converting the | |
| 523 | -# LibreOffice document storage/form.odt to PDF and then manually | |
| 524 | -# modifying the resulting PDF in various ways. That file would be good | |
| 525 | -# starting point for generation of more complex forms should that be | |
| 526 | -# required in the future. The file storage/form.pdf is a direct export | |
| 527 | -# from LibreOffice with no modifications. The files | |
| 528 | -# storage/field-types.odt and storage/field-types.pdf are the basis of | |
| 529 | -# field-types.pdf used elsewhere in the test suite. | |
| 530 | - | |
| 531 | -foreach my $f (@form_tests) | |
| 532 | -{ | |
| 533 | - $td->runtest("form test: $f", | |
| 534 | - {$td->COMMAND => "test_driver 43 $f.pdf"}, | |
| 535 | - {$td->FILE => "form-$f.out", $td->EXIT_STATUS => 0}, | |
| 536 | - $td->NORMALIZE_NEWLINES); | |
| 537 | -} | |
| 538 | - | |
| 539 | -$td->runtest("fill fields", | |
| 540 | - {$td->COMMAND => "test_driver 44 form-no-need-appearances.pdf"}, | |
| 541 | - {$td->FILE => "form-no-need-appearances.out", | |
| 542 | - $td->EXIT_STATUS => 0}, | |
| 543 | - $td->NORMALIZE_NEWLINES); | |
| 544 | -$td->runtest("compare files", | |
| 545 | - {$td->FILE => "a.pdf"}, | |
| 546 | - {$td->FILE => "form-no-need-appearances-filled.pdf"}); | |
| 547 | - | |
| 548 | -$td->runtest("button fields", | |
| 549 | - {$td->COMMAND => "test_driver 51 button-set.pdf"}, | |
| 550 | - {$td->FILE => "button-set.out", $td->EXIT_STATUS => 0}, | |
| 551 | - $td->NORMALIZE_NEWLINES); | |
| 552 | -$td->runtest("compare files", | |
| 553 | - {$td->FILE => "a.pdf"}, | |
| 554 | - {$td->FILE => "button-set-out.pdf"}); | |
| 555 | - | |
| 556 | -$td->runtest("broken button fields", | |
| 557 | - {$td->COMMAND => "test_driver 51 button-set-broken.pdf"}, | |
| 558 | - {$td->FILE => "button-set-broken.out", $td->EXIT_STATUS => 0}, | |
| 559 | - $td->NORMALIZE_NEWLINES); | |
| 560 | -$td->runtest("compare files", | |
| 561 | - {$td->FILE => "a.pdf"}, | |
| 562 | - {$td->FILE => "button-set-broken-out.pdf"}); | |
| 563 | - | |
| 564 | -show_ntests(); | |
| 565 | -# ---------- | |
| 566 | -$td->notify("--- Appearance Streams ---"); | |
| 567 | -$n_tests += 12; | |
| 568 | - | |
| 569 | -foreach my $f ('need-appearances', | |
| 570 | - 'need-appearances-more', | |
| 571 | - 'need-appearances-more2', | |
| 572 | - 'need-appearances-more3') | |
| 573 | -{ | |
| 574 | - $td->runtest("generate appearances and flatten ($f)", | |
| 575 | - {$td->COMMAND => | |
| 576 | - "qpdf --qdf --no-original-object-ids --static-id" . | |
| 577 | - " --generate-appearances --flatten-annotations=all" . | |
| 578 | - " $f.pdf a.pdf"}, | |
| 579 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 580 | - $td->NORMALIZE_NEWLINES); | |
| 581 | - my $exp = 'appearances-a'; | |
| 582 | - if ($f =~ m/appearances(-.*)$/) | |
| 583 | - { | |
| 584 | - $exp .= $1; | |
| 585 | - } | |
| 586 | - $exp .= '.pdf'; | |
| 587 | - $td->runtest("compare files", | |
| 588 | - {$td->FILE => "a.pdf"}, | |
| 589 | - {$td->FILE => $exp}); | |
| 590 | -} | |
| 591 | - | |
| 592 | -$td->runtest("more choices", | |
| 593 | - {$td->COMMAND => | |
| 594 | - "qpdf --qdf --no-original-object-ids --static-id" . | |
| 595 | - " --generate-appearances" . | |
| 596 | - " more-choices.pdf b.pdf"}, | |
| 597 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 598 | - $td->NORMALIZE_NEWLINES); | |
| 599 | -# b.pdf still has forms | |
| 600 | -$td->runtest("compare files", | |
| 601 | - {$td->FILE => "b.pdf"}, | |
| 602 | - {$td->FILE => "appearances-b.pdf"}); | |
| 603 | - | |
| 604 | -my @choice_values = qw(1 2 11 12 quack); | |
| 605 | -$n_tests += 3 * scalar(@choice_values); | |
| 606 | -foreach my $i (@choice_values) | |
| 607 | -{ | |
| 608 | - # b.pdf was generated by qpdf and needs appearances | |
| 609 | - # test_driver 52 writes a.pdf | |
| 610 | - $td->runtest("set value to $i", | |
| 611 | - {$td->COMMAND => "test_driver 52 b.pdf $i"}, | |
| 612 | - {$td->STRING => "setting list1 value\ntest 52 done\n", | |
| 613 | - $td->EXIT_STATUS => 0}, | |
| 614 | - $td->NORMALIZE_NEWLINES); | |
| 615 | - $td->runtest("regenerate appearances", | |
| 616 | - {$td->COMMAND => | |
| 617 | - "qpdf --qdf --no-original-object-ids --static-id" . | |
| 618 | - " --generate-appearances" . | |
| 619 | - " a.pdf b.pdf"}, | |
| 620 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 621 | - $td->NORMALIZE_NEWLINES); | |
| 622 | - $td->runtest("compare files", | |
| 623 | - {$td->FILE => "b.pdf"}, | |
| 624 | - {$td->FILE => "appearances-$i.pdf"}); | |
| 625 | -} | |
| 626 | - | |
| 627 | -$td->runtest("Update resources from /DR", | |
| 628 | - {$td->COMMAND => | |
| 629 | - "qpdf --qdf --no-original-object-ids --static-id" . | |
| 630 | - " --generate-appearances" . | |
| 631 | - " resource-from-dr.pdf a.pdf"}, | |
| 632 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 633 | - $td->NORMALIZE_NEWLINES); | |
| 634 | -$td->runtest("compare files", | |
| 635 | - {$td->FILE => "a.pdf"}, | |
| 636 | - {$td->FILE => "resource-from-dr-out.pdf"}); | |
| 637 | - | |
| 638 | -show_ntests(); | |
| 639 | -# ---------- | |
| 640 | -$td->notify("--- Form XObject, underlay, overlay ---"); | |
| 641 | -$n_tests += 22; | |
| 642 | - | |
| 643 | -$td->runtest("form xobject creation", | |
| 644 | - {$td->COMMAND => "test_driver 55 fxo-red.pdf"}, | |
| 645 | - {$td->STRING => "test 55 done\n", $td->EXIT_STATUS => 0}, | |
| 646 | - $td->NORMALIZE_NEWLINES); | |
| 647 | -$td->runtest("compare files", | |
| 648 | - {$td->FILE => "a.pdf"}, | |
| 649 | - {$td->FILE => "form-xobjects-out.pdf"}); | |
| 650 | -foreach (my $i = 56; $i <= 59; ++$i) | |
| 651 | -{ | |
| 652 | - # See comments in test_driver.cc for a verbal description of what | |
| 653 | - # the resulting files should look like. | |
| 654 | - $td->runtest("overlay transformations", | |
| 655 | - {$td->COMMAND => "test_driver $i fxo-red.pdf fxo-blue.pdf"}, | |
| 656 | - {$td->STRING => "test $i done\n", $td->EXIT_STATUS => 0}, | |
| 657 | - $td->NORMALIZE_NEWLINES); | |
| 658 | - $td->runtest("compare files", | |
| 659 | - {$td->FILE => "a.pdf"}, | |
| 660 | - {$td->FILE => "fx-overlay-$i.pdf"}); | |
| 661 | -} | |
| 662 | -foreach (my $i = 64; $i <= 67; ++$i) | |
| 663 | -{ | |
| 664 | - # See comments in test_driver.cc for a verbal description of what | |
| 665 | - # the resulting files should look like. | |
| 666 | - $td->runtest("overlay shrink/expand", | |
| 667 | - {$td->COMMAND => | |
| 668 | - "test_driver $i fxo-bigsmall.pdf fxo-smallbig.pdf"}, | |
| 669 | - {$td->STRING => "test $i done\n", $td->EXIT_STATUS => 0}, | |
| 670 | - $td->NORMALIZE_NEWLINES); | |
| 671 | - $td->runtest("compare files", | |
| 672 | - {$td->FILE => "a.pdf"}, | |
| 673 | - {$td->FILE => "fx-overlay-$i.pdf"}); | |
| 674 | -} | |
| 675 | - | |
| 676 | -my @uo_cases = ( | |
| 677 | - '--underlay fxo-green.pdf --repeat=z --to=1-14 --' . | |
| 678 | - ' --overlay fxo-blue.pdf --', # 1 | |
| 679 | - '--overlay fxo-green.pdf --from= --repeat=r2,r1 --' . | |
| 680 | - ' --underlay fxo-blue.pdf --from=z-1 --', # 2 | |
| 681 | - '--overlay fxo-green.pdf --from= --repeat=r2,r1 --' . | |
| 682 | - ' --underlay fxo-blue.pdf --from=z-1 -- --coalesce-contents', # 3 | |
| 683 | - '--overlay fxo-green.pdf --', # 4 | |
| 684 | - '--underlay fxo-green.pdf --to=3-7 --', # 5 | |
| 685 | - '--overlay fxo-blue.pdf --to=1,1,1,1 --from=1-4 --' . | |
| 686 | - ' --pages . 1 --', #6 | |
| 687 | - '--overlay 20-pages.pdf --password=user --', #7 | |
| 688 | - ); | |
| 689 | -$n_tests += 2 * scalar(@uo_cases); | |
| 690 | -for (my $i = 1; $i <= scalar(@uo_cases); ++$i) | |
| 691 | -{ | |
| 692 | - my $args = $uo_cases[$i-1]; | |
| 693 | - my $outbase = "uo-$i"; | |
| 694 | - $td->runtest("overlay/underlay $i", | |
| 695 | - {$td->COMMAND => | |
| 696 | - "qpdf --static-id --qdf --no-original-object-ids" . | |
| 697 | - " --verbose fxo-red.pdf a.pdf $args"}, | |
| 698 | - {$td->FILE => "$outbase.out", $td->EXIT_STATUS => 0}, | |
| 699 | - $td->NORMALIZE_NEWLINES); | |
| 700 | - $td->runtest("compare files", | |
| 701 | - {$td->FILE => "a.pdf"}, | |
| 702 | - {$td->FILE => "$outbase.pdf"}); | |
| 703 | -} | |
| 704 | -$td->runtest("foreach", | |
| 705 | - {$td->COMMAND => "test_driver 71 nested-form-xobjects.pdf"}, | |
| 706 | - {$td->FILE => "nested-form-xobjects.out", | |
| 707 | - $td->EXIT_STATUS => 0}, | |
| 708 | - $td->NORMALIZE_NEWLINES); | |
| 709 | -$td->runtest("page operations on form xobject", | |
| 710 | - {$td->COMMAND => "test_driver 72 nested-form-xobjects.pdf"}, | |
| 711 | - {$td->FILE => "page-ops-on-form-xobject.out", | |
| 712 | - $td->EXIT_STATUS => 0}, | |
| 713 | - $td->NORMALIZE_NEWLINES); | |
| 714 | -$td->runtest("overlay on page with no resources", | |
| 715 | - {$td->COMMAND => | |
| 716 | - "qpdf --deterministic-id page-with-no-resources.pdf" . | |
| 717 | - " --overlay minimal.pdf -- a.pdf"}, | |
| 718 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 719 | - $td->NORMALIZE_NEWLINES); | |
| 720 | -$td->runtest("check overlay with no resources output", | |
| 721 | - {$td->FILE => "a.pdf"}, | |
| 722 | - {$td->FILE => "overlay-no-resources.pdf"}); | |
| 723 | - | |
| 724 | -show_ntests(); | |
| 725 | -# ---------- | |
| 726 | -$td->notify("--- File Attachments ---"); | |
| 727 | -$n_tests += 37; | |
| 728 | - | |
| 729 | -open(F, ">auto-txt") or die; | |
| 730 | -print F "from file"; | |
| 731 | -close(F); | |
| 732 | -$td->runtest("attachments", | |
| 733 | - {$td->COMMAND => "test_driver 76 minimal.pdf auto-txt"}, | |
| 734 | - {$td->FILE => "test76.out", $td->EXIT_STATUS => 0}, | |
| 735 | - $td->NORMALIZE_NEWLINES); | |
| 736 | -$td->runtest("show attachment", | |
| 737 | - {$td->COMMAND => "qpdf --show-attachment=att1 a.pdf"}, | |
| 738 | - {$td->STRING => "from file", $td->EXIT_STATUS => 0}, | |
| 739 | - $td->NORMALIZE_NEWLINES); | |
| 740 | -$td->runtest("check output", | |
| 741 | - {$td->FILE => "a.pdf"}, | |
| 742 | - {$td->FILE => "test76.pdf"}); | |
| 743 | -$td->runtest("list attachments", | |
| 744 | - {$td->COMMAND => "qpdf --list-attachments a.pdf"}, | |
| 745 | - {$td->FILE => "test76-list.out", $td->EXIT_STATUS => 0}, | |
| 746 | - $td->NORMALIZE_NEWLINES); | |
| 747 | -$td->runtest("list attachments verbose", | |
| 748 | - {$td->COMMAND => "qpdf --list-attachments --verbose a.pdf"}, | |
| 749 | - {$td->FILE => "test76-list-verbose.out", $td->EXIT_STATUS => 0}, | |
| 750 | - $td->NORMALIZE_NEWLINES); | |
| 751 | -$td->runtest("attachments json", | |
| 752 | - {$td->COMMAND => "qpdf --json=1 --json-key=attachments a.pdf"}, | |
| 753 | - {$td->FILE => "test76-json.out", $td->EXIT_STATUS => 0}, | |
| 754 | - $td->NORMALIZE_NEWLINES); | |
| 755 | -$td->runtest("remove attachment (test_driver)", | |
| 756 | - {$td->COMMAND => "test_driver 77 test76.pdf"}, | |
| 757 | - {$td->STRING => "test 77 done\n", $td->EXIT_STATUS => 0}, | |
| 758 | - $td->NORMALIZE_NEWLINES); | |
| 759 | -$td->runtest("check output", | |
| 760 | - {$td->FILE => "a.pdf"}, | |
| 761 | - {$td->FILE => "test77.pdf"}); | |
| 762 | -$td->runtest("remove attachment (cli)", | |
| 763 | - {$td->COMMAND => "qpdf --remove-attachment=att2 test76.pdf" . | |
| 764 | - " --static-id --qdf --verbose b.pdf"}, | |
| 765 | - {$td->FILE => "remove-attachment.out", $td->EXIT_STATUS => 0}, | |
| 766 | - $td->NORMALIZE_NEWLINES); | |
| 767 | -$td->runtest("check output", | |
| 768 | - {$td->FILE => "b.pdf"}, | |
| 769 | - {$td->FILE => "test77.pdf"}); | |
| 770 | -$td->runtest("show missing attachment", | |
| 771 | - {$td->COMMAND => "qpdf --show-attachment=att2 b.pdf"}, | |
| 772 | - {$td->STRING => "qpdf: attachment att2 not found\n", | |
| 773 | - $td->EXIT_STATUS => 2}, | |
| 774 | - $td->NORMALIZE_NEWLINES); | |
| 775 | -$td->runtest("remove missing attachment", | |
| 776 | - {$td->COMMAND => "qpdf --remove-attachment=att2 b.pdf c.pdf"}, | |
| 777 | - {$td->STRING => "qpdf: attachment att2 not found\n", | |
| 778 | - $td->EXIT_STATUS => 2}, | |
| 779 | - $td->NORMALIZE_NEWLINES); | |
| 780 | - | |
| 781 | -$td->runtest("add attachment: bad creation date", | |
| 782 | - {$td->COMMAND => "qpdf minimal.pdf a.pdf" . | |
| 783 | - " --add-attachment auto-txt --creationdate=potato --"}, | |
| 784 | - {$td->REGEXP => ".*potato is not a valid PDF timestamp.*", | |
| 785 | - $td->EXIT_STATUS => 2}, | |
| 786 | - $td->NORMALIZE_NEWLINES); | |
| 787 | -$td->runtest("add attachment: bad mod date", | |
| 788 | - {$td->COMMAND => "qpdf minimal.pdf a.pdf" . | |
| 789 | - " --add-attachment auto-txt --moddate=potato --"}, | |
| 790 | - {$td->REGEXP => ".*potato is not a valid PDF timestamp.*", | |
| 791 | - $td->EXIT_STATUS => 2}, | |
| 792 | - $td->NORMALIZE_NEWLINES); | |
| 793 | -$td->runtest("add attachment: bad mod date", | |
| 794 | - {$td->COMMAND => "qpdf minimal.pdf a.pdf" . | |
| 795 | - " --add-attachment auto-txt --mimetype=potato --"}, | |
| 796 | - {$td->REGEXP => | |
| 797 | - ".*mime type should be specified as type/subtype.*", | |
| 798 | - $td->EXIT_STATUS => 2}, | |
| 799 | - $td->NORMALIZE_NEWLINES); | |
| 800 | -$td->runtest("add attachment: trailing slash", | |
| 801 | - {$td->COMMAND => "qpdf minimal.pdf a.pdf" . | |
| 802 | - " --add-attachment --"}, | |
| 803 | - {$td->REGEXP => ".*add attachment: no file specified.*", | |
| 804 | - $td->EXIT_STATUS => 2}, | |
| 805 | - $td->NORMALIZE_NEWLINES); | |
| 806 | - | |
| 807 | -foreach my $i (qw(1 2 3)) | |
| 808 | -{ | |
| 809 | - open(F, ">auto-$i") or die; | |
| 810 | - print F "attachment $i"; | |
| 811 | - close(F); | |
| 812 | -} | |
| 813 | -my @dates = ("--creationdate=D:20210210091359-05'00'", | |
| 814 | - "--moddate=D:20210210141359Z"); | |
| 815 | -$td->runtest("add attachments", | |
| 816 | - {$td->COMMAND => | |
| 817 | - [qw(qpdf minimal.pdf a.pdf --no-original-object-ids), | |
| 818 | - qw(--verbose --static-id --qdf), | |
| 819 | - qw(--add-attachment ./auto-1), @dates, | |
| 820 | - qw(--mimetype=text/plain --), | |
| 821 | - qw(--add-attachment ./auto-2 --key=auto-Two), @dates, '--', | |
| 822 | - qw(--add-attachment ./auto-3 --filename=auto-Three.txt), | |
| 823 | - @dates, '--description=two words', '--']}, | |
| 824 | - {$td->FILE => "add-attachments-1.out", $td->EXIT_STATUS => 0}, | |
| 825 | - $td->NORMALIZE_NEWLINES); | |
| 826 | -$td->runtest("list attachments", | |
| 827 | - {$td->COMMAND => "qpdf --list-attachments a.pdf --verbose"}, | |
| 828 | - {$td->FILE => "list-attachments-1.out", $td->EXIT_STATUS => 0}, | |
| 829 | - $td->NORMALIZE_NEWLINES); | |
| 830 | -$td->runtest("check output", | |
| 831 | - {$td->FILE => "a.pdf"}, | |
| 832 | - {$td->FILE => "add-attachments-1.pdf"}, | |
| 833 | - $td->NORMALIZE_NEWLINES); | |
| 834 | -$td->runtest("add attachments: duplicate", | |
| 835 | - {$td->COMMAND => | |
| 836 | - "qpdf a.pdf b.pdf --verbose --add-attachment ./auto-1 --"}, | |
| 837 | - {$td->FILE => "add-attachments-duplicate.out", | |
| 838 | - $td->EXIT_STATUS => 2}, | |
| 839 | - $td->NORMALIZE_NEWLINES); | |
| 840 | -$td->runtest("add attachments: replace", | |
| 841 | - {$td->COMMAND => | |
| 842 | - [qw(qpdf a.pdf b.pdf --no-original-object-ids), | |
| 843 | - qw(--verbose --static-id --qdf), | |
| 844 | - qw(--add-attachment ./auto-2 --key=auto-1 --replace), | |
| 845 | - @dates, '--']}, | |
| 846 | - {$td->FILE => "add-attachments-2.out", $td->EXIT_STATUS => 0}, | |
| 847 | - $td->NORMALIZE_NEWLINES); | |
| 848 | -$td->runtest("list attachments", | |
| 849 | - {$td->COMMAND => "qpdf --list-attachments b.pdf --verbose"}, | |
| 850 | - {$td->FILE => "list-attachments-3.out", $td->EXIT_STATUS => 0}, | |
| 851 | - $td->NORMALIZE_NEWLINES); | |
| 852 | -$td->runtest("check output", | |
| 853 | - {$td->FILE => "b.pdf"}, | |
| 854 | - {$td->FILE => "add-attachments-2.pdf"}, | |
| 855 | - $td->NORMALIZE_NEWLINES); | |
| 856 | -$td->runtest("copy attachments", | |
| 857 | - {$td->COMMAND => | |
| 858 | - "qpdf --verbose --no-original-object-ids" . | |
| 859 | - " --static-id --qdf minimal.pdf b.pdf" . | |
| 860 | - " --copy-attachments-from a.pdf --"}, | |
| 861 | - {$td->FILE => "copy-attachments-1.out", $td->EXIT_STATUS => 0}, | |
| 862 | - $td->NORMALIZE_NEWLINES); | |
| 863 | -$td->runtest("list attachments", | |
| 864 | - {$td->COMMAND => "qpdf --list-attachments b.pdf --verbose"}, | |
| 865 | - {$td->FILE => "list-attachments-1.out", $td->EXIT_STATUS => 0}, | |
| 866 | - $td->NORMALIZE_NEWLINES); | |
| 867 | -$td->runtest("check output", | |
| 868 | - {$td->FILE => "b.pdf"}, | |
| 869 | - {$td->FILE => "add-attachments-1.pdf"}, | |
| 870 | - $td->NORMALIZE_NEWLINES); | |
| 871 | -$td->runtest("copy attachments: duplicate", | |
| 872 | - {$td->COMMAND => | |
| 873 | - "qpdf --verbose --no-original-object-ids" . | |
| 874 | - " --static-id --qdf a.pdf c.pdf" . | |
| 875 | - " --copy-attachments-from b.pdf --"}, | |
| 876 | - {$td->FILE => "copy-attachments-duplicate.out", | |
| 877 | - $td->EXIT_STATUS => 2}, | |
| 878 | - $td->NORMALIZE_NEWLINES); | |
| 879 | -$td->runtest("copy attachments: prefix", | |
| 880 | - {$td->COMMAND => | |
| 881 | - "qpdf --verbose --no-original-object-ids" . | |
| 882 | - " --static-id --qdf a.pdf c.pdf" . | |
| 883 | - " --copy-attachments-from b.pdf --prefix=1- --"}, | |
| 884 | - {$td->FILE => "copy-attachments-2.out", $td->EXIT_STATUS => 0}, | |
| 885 | - $td->NORMALIZE_NEWLINES); | |
| 886 | -$td->runtest("list attachments", | |
| 887 | - {$td->COMMAND => "qpdf --list-attachments c.pdf --verbose"}, | |
| 888 | - {$td->FILE => "list-attachments-2.out", $td->EXIT_STATUS => 0}, | |
| 889 | - $td->NORMALIZE_NEWLINES); | |
| 890 | -$td->runtest("check output", | |
| 891 | - {$td->FILE => "c.pdf"}, | |
| 892 | - {$td->FILE => "copy-attachments-2.pdf"}, | |
| 893 | - $td->NORMALIZE_NEWLINES); | |
| 894 | -$td->runtest("add attachments: current date", | |
| 895 | - {$td->COMMAND => | |
| 896 | - [qw(qpdf minimal.pdf a.pdf --encrypt u o 256 --), | |
| 897 | - qw(--verbose --add-attachment ./auto-1 --)]}, | |
| 898 | - {$td->FILE => "add-attachments-3.out", $td->EXIT_STATUS => 0}, | |
| 899 | - $td->NORMALIZE_NEWLINES); | |
| 900 | -$td->runtest("list attachments", | |
| 901 | - {$td->COMMAND => | |
| 902 | - "qpdf --password=u --list-attachments a.pdf --verbose"}, | |
| 903 | - {$td->FILE => "list-attachments-4.out", $td->EXIT_STATUS => 0}, | |
| 904 | - $td->NORMALIZE_NEWLINES); | |
| 905 | -# The object to show here is the one in list-attachments-4.out | |
| 906 | -$td->runtest("check dates", | |
| 907 | - {$td->COMMAND => "qpdf --show-object=6 a.pdf --password=u"}, | |
| 908 | - {$td->REGEXP => ".*CreationDate \\(D:\\d+.*ModDate \\(D:\\d+.*", | |
| 909 | - $td->EXIT_STATUS => 0}, | |
| 910 | - $td->NORMALIZE_NEWLINES); | |
| 911 | -$td->runtest("remove multiple attachments", | |
| 912 | - {$td->COMMAND => | |
| 913 | - "qpdf --verbose --static-id add-attachments-1.pdf a.pdf" . | |
| 914 | - " --remove-attachment=auto-1 --remove-attachment=auto-Two"}, | |
| 915 | - {$td->FILE => "remove-multiple-attachments.out", | |
| 916 | - $td->EXIT_STATUS => 0}, | |
| 917 | - $td->NORMALIZE_NEWLINES); | |
| 918 | -$td->runtest("check output", | |
| 919 | - {$td->FILE => "a.pdf"}, | |
| 920 | - {$td->FILE => "remove-multiple-attachments.pdf"}); | |
| 921 | -$td->runtest("remove multiple attachments (json)", | |
| 922 | - {$td->COMMAND => | |
| 923 | - "qpdf --job-json-file=remove-multiple-attachments.json"}, | |
| 924 | - {$td->FILE => "remove-multiple-attachments-json.out", | |
| 925 | - $td->EXIT_STATUS => 0}, | |
| 926 | - $td->NORMALIZE_NEWLINES); | |
| 927 | -$td->runtest("check output", | |
| 928 | - {$td->FILE => "b.pdf"}, | |
| 929 | - {$td->FILE => "remove-multiple-attachments.pdf"}); | |
| 930 | - | |
| 931 | -show_ntests(); | |
| 932 | -# ---------- | |
| 933 | -$td->notify("--- Stream Replacement Tests ---"); | |
| 934 | -$n_tests += 10; | |
| 935 | - | |
| 936 | -$td->runtest("replace stream data", | |
| 937 | - {$td->COMMAND => "test_driver 7 qstream.pdf"}, | |
| 938 | - {$td->STRING => "test 7 done\n", $td->EXIT_STATUS => 0}, | |
| 939 | - $td->NORMALIZE_NEWLINES); | |
| 940 | -$td->runtest("check output", | |
| 941 | - {$td->FILE => "a.pdf"}, | |
| 942 | - {$td->FILE => "replaced-stream-data.pdf"}); | |
| 943 | -$td->runtest("replace stream data compressed", | |
| 944 | - {$td->COMMAND => "test_driver 8 qstream.pdf"}, | |
| 945 | - {$td->FILE => "test8.out", $td->EXIT_STATUS => 0}, | |
| 946 | - $td->NORMALIZE_NEWLINES); | |
| 947 | -$td->runtest("check output", | |
| 948 | - {$td->FILE => "a.pdf"}, | |
| 949 | - {$td->FILE => "replaced-stream-data-flate.pdf"}); | |
| 950 | -$td->runtest("new streams", | |
| 951 | - {$td->COMMAND => "test_driver 9 minimal.pdf"}, | |
| 952 | - {$td->FILE => "test9.out", $td->EXIT_STATUS => 0}, | |
| 953 | - $td->NORMALIZE_NEWLINES); | |
| 954 | -$td->runtest("new stream", | |
| 955 | - {$td->FILE => "a.pdf"}, | |
| 956 | - {$td->FILE => "new-streams.pdf"}); | |
| 957 | -$td->runtest("add page contents", | |
| 958 | - {$td->COMMAND => "test_driver 10 minimal.pdf"}, | |
| 959 | - {$td->STRING => "test 10 done\n", $td->EXIT_STATUS => 0}, | |
| 960 | - $td->NORMALIZE_NEWLINES); | |
| 961 | -$td->runtest("new stream", | |
| 962 | - {$td->FILE => "a.pdf"}, | |
| 963 | - {$td->FILE => "add-contents.pdf"}); | |
| 964 | -$td->runtest("functional replace stream data", | |
| 965 | - {$td->COMMAND => "test_driver 78 minimal.pdf"}, | |
| 966 | - {$td->FILE => "test78.out", $td->EXIT_STATUS => 0}, | |
| 967 | - $td->NORMALIZE_NEWLINES); | |
| 968 | -$td->runtest("check output", | |
| 969 | - {$td->FILE => "a.pdf"}, | |
| 970 | - {$td->FILE => "test78.pdf"}); | |
| 971 | - | |
| 972 | -show_ntests(); | |
| 973 | -# ---------- | |
| 974 | -$td->notify("--- Extensions Dictionary Tests ---"); | |
| 975 | -my @ext_inputs = ('minimal.pdf', 'extensions-adbe.pdf', | |
| 976 | - 'extensions-other.pdf', 'extensions-adbe-other.pdf'); | |
| 977 | -my @new_versions = ('1.3', '1.6', '1.7.1', '1.7.2', '1.7.3', | |
| 978 | - '1.8', '1.8.0', '1.8.2', '1.8.5'); | |
| 979 | -$n_tests += (4 * @new_versions + 3) * @ext_inputs; | |
| 980 | -foreach my $input (@ext_inputs) | |
| 981 | -{ | |
| 982 | - my $base = $input; | |
| 983 | - $base =~ s/\.pdf$//; | |
| 984 | - if ($base eq 'minimal') | |
| 985 | - { | |
| 986 | - $base = 'extensions-none'; | |
| 987 | - } | |
| 988 | - foreach my $version (@new_versions) | |
| 989 | - { | |
| 990 | - foreach my $op (qw(min force)) | |
| 991 | - { | |
| 992 | - $td->runtest("$input: $op version to $version", | |
| 993 | - {$td->COMMAND => | |
| 994 | - "qpdf --static-id" . | |
| 995 | - " --$op-version=$version $input a.pdf"}, | |
| 996 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 997 | - $td->runtest("check version information ($op $version)", | |
| 998 | - {$td->COMMAND => "test_driver 34 a.pdf"}, | |
| 999 | - {$td->FILE => "$base-$op-$version.out", | |
| 1000 | - $td->EXIT_STATUS => 0}, | |
| 1001 | - $td->NORMALIZE_NEWLINES); | |
| 1002 | - if (($op eq 'force') && ($version eq '1.8.5')) | |
| 1003 | - { | |
| 1004 | - # Look at the actual file for a few cases to make sure | |
| 1005 | - # qdf and non-qdf output are okay | |
| 1006 | - $td->runtest("check file", | |
| 1007 | - {$td->FILE => "a.pdf"}, | |
| 1008 | - {$td->FILE => "$base-$op-$version.pdf"}); | |
| 1009 | - $td->runtest("$input: $op version to $version", | |
| 1010 | - {$td->COMMAND => | |
| 1011 | - "qpdf --qdf --static-id" . | |
| 1012 | - " --$op-version=$version $input a.qdf"}, | |
| 1013 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 1014 | - $td->runtest("check file", | |
| 1015 | - {$td->FILE => "a.qdf"}, | |
| 1016 | - {$td->FILE => "$base-$op-$version.qdf"}); | |
| 1017 | - } | |
| 1018 | - } | |
| 1019 | - } | |
| 1020 | -} | |
| 1021 | -show_ntests(); | |
| 1022 | -# ---------- | |
| 1023 | -$td->notify("--- Number and Name Trees ---"); | |
| 1024 | -$n_tests += 6; | |
| 1025 | - | |
| 1026 | -$td->runtest("number trees", | |
| 1027 | - {$td->COMMAND => "test_driver 46 number-tree.pdf"}, | |
| 1028 | - {$td->FILE => "number-tree.out", $td->EXIT_STATUS => 0}, | |
| 1029 | - $td->NORMALIZE_NEWLINES); | |
| 1030 | -$td->runtest("name trees", | |
| 1031 | - {$td->COMMAND => "test_driver 48 name-tree.pdf"}, | |
| 1032 | - {$td->FILE => "name-tree.out", $td->EXIT_STATUS => 0}, | |
| 1033 | - $td->NORMALIZE_NEWLINES); | |
| 1034 | -$td->runtest("nntree split", | |
| 1035 | - {$td->COMMAND => "test_driver 74 split-nntree.pdf"}, | |
| 1036 | - {$td->FILE => "split-nntree.out", $td->EXIT_STATUS => 0}, | |
| 1037 | - $td->NORMALIZE_NEWLINES); | |
| 1038 | -$td->runtest("check file", | |
| 1039 | - {$td->FILE => "a.pdf"}, | |
| 1040 | - {$td->FILE => "split-nntree-out.pdf"}); | |
| 1041 | -$td->runtest("nntree erase", | |
| 1042 | - {$td->COMMAND => "test_driver 75 erase-nntree.pdf"}, | |
| 1043 | - {$td->FILE => "erase-nntree.out", $td->EXIT_STATUS => 0}, | |
| 1044 | - $td->NORMALIZE_NEWLINES); | |
| 1045 | -$td->runtest("check file", | |
| 1046 | - {$td->FILE => "a.pdf"}, | |
| 1047 | - {$td->FILE => "erase-nntree-out.pdf"}); | |
| 1048 | - | |
| 1049 | -show_ntests(); | |
| 1050 | -# ---------- | |
| 1051 | -$td->notify("--- Page Labels ---"); | |
| 1052 | -$n_tests += 3; | |
| 1053 | - | |
| 1054 | -$td->runtest("complex page labels", | |
| 1055 | - {$td->COMMAND => "test_driver 47 page-labels-num-tree.pdf"}, | |
| 1056 | - {$td->FILE => "page-labels-num-tree.out", $td->EXIT_STATUS => 0}, | |
| 1057 | - $td->NORMALIZE_NEWLINES); | |
| 1058 | -$td->runtest("no zero entry for page labels", | |
| 1059 | - {$td->COMMAND => "test_driver 47 page-labels-no-zero.pdf"}, | |
| 1060 | - {$td->FILE => "page-labels-no-zero.out", $td->EXIT_STATUS => 0}, | |
| 1061 | - $td->NORMALIZE_NEWLINES); | |
| 1062 | -$td->runtest("no page labels", | |
| 1063 | - {$td->COMMAND => "test_driver 47 minimal.pdf"}, | |
| 1064 | - {$td->FILE => "no-page-labels.out", $td->EXIT_STATUS => 0}, | |
| 1065 | - $td->NORMALIZE_NEWLINES); | |
| 1066 | - | |
| 1067 | -show_ntests(); | |
| 1068 | -# ---------- | |
| 1069 | -$td->notify("--- Outlines ---"); | |
| 1070 | -my @outline_files = ( | |
| 1071 | - 'page-labels-and-outlines', | |
| 1072 | - 'outlines-with-actions', | |
| 1073 | - 'outlines-with-old-root-dests', | |
| 1074 | - 'outlines-with-loop', | |
| 1075 | - ); | |
| 1076 | -$n_tests += scalar(@outline_files); | |
| 1077 | -foreach my $f (@outline_files) | |
| 1078 | -{ | |
| 1079 | - $td->runtest("outlines: $f", | |
| 1080 | - {$td->COMMAND => "test_driver 49 $f.pdf"}, | |
| 1081 | - {$td->FILE => "$f.out", $td->EXIT_STATUS => 0}, | |
| 1082 | - $td->NORMALIZE_NEWLINES); | |
| 1083 | -} | |
| 1084 | - | |
| 1085 | -show_ntests(); | |
| 1086 | -# ---------- | |
| 1087 | -$td->notify("--- JSON Tests ---"); | |
| 1088 | -my @json_files = ( | |
| 1089 | - ['outlines-with-actions', []], | |
| 1090 | - ['outlines-with-old-root-dests', []], | |
| 1091 | - ['page-labels-and-outlines', []], | |
| 1092 | - ['page-labels-num-tree', []], | |
| 1093 | - ['image-streams', []], | |
| 1094 | - ['image-streams-small', []], | |
| 1095 | - ['field-types', []], | |
| 1096 | - ['field-types', ['--show-encryption-key']], | |
| 1097 | - ['image-streams', ['--decode-level=all']], | |
| 1098 | - ['image-streams', ['--decode-level=specialized']], | |
| 1099 | - ['page-labels-and-outlines', ['--json-key=qpdf']], | |
| 1100 | - ['page-labels-and-outlines', ['--json-key=pages']], | |
| 1101 | - ['page-labels-and-outlines', ['--json-key=pagelabels']], | |
| 1102 | - ['page-labels-and-outlines', ['--json-key=outlines']], | |
| 1103 | - ['page-labels-and-outlines', | |
| 1104 | - ['--json-key=outlines', '--json-key=pages']], | |
| 1105 | - ['page-labels-and-outlines', | |
| 1106 | - ['--json-key=qpdf', '--json-object=trailer']], | |
| 1107 | - ['page-labels-and-outlines', | |
| 1108 | - ['--json-key=qpdf', '--json-object=trailer', '--json-object=2 0 R']], | |
| 1109 | - ['field-types', ['--json-key=acroform']], | |
| 1110 | - ['need-appearances', ['--json-key=acroform']], | |
| 1111 | - ['V4-aes', ['--json-key=encrypt']], | |
| 1112 | - ['V4-aes', ['--json-key=encrypt', '--show-encryption-key']], | |
| 1113 | -); | |
| 1114 | -$n_tests += 25 + (2 * scalar(@json_files)); | |
| 1115 | -foreach my $d (@json_files) | |
| 1116 | -{ | |
| 1117 | - my ($file, $xargs) = @$d; | |
| 1118 | - my $out = "json-$file"; | |
| 1119 | - my @v1_xargs = (); | |
| 1120 | - foreach my $x (@$xargs) | |
| 1121 | - { | |
| 1122 | - my $y = $x; | |
| 1123 | - $y =~ s/^.*=//; | |
| 1124 | - $y =~ s/\s.*//; | |
| 1125 | - $out .= "-$y"; | |
| 1126 | - if ($x eq '--json-key=qpdf') | |
| 1127 | - { | |
| 1128 | - push(@v1_xargs, '--json-key=objects'); | |
| 1129 | - } | |
| 1130 | - else | |
| 1131 | - { | |
| 1132 | - push(@v1_xargs, $x); | |
| 1133 | - } | |
| 1134 | - } | |
| 1135 | - my $in = "$file.pdf"; | |
| 1136 | - $td->runtest("json v1 $out", | |
| 1137 | - {$td->COMMAND => | |
| 1138 | - ['qpdf', '--json=1', '--test-json-schema', | |
| 1139 | - @v1_xargs, $in]}, | |
| 1140 | - {$td->FILE => "$out-v1.out", $td->EXIT_STATUS => 0}, | |
| 1141 | - $td->NORMALIZE_NEWLINES); | |
| 1142 | - $td->runtest("json v2 $out", | |
| 1143 | - {$td->COMMAND => | |
| 1144 | - ['qpdf', '--json=2', '--test-json-schema', @$xargs, $in]}, | |
| 1145 | - {$td->FILE => "$out-v2.out", $td->EXIT_STATUS => 0}, | |
| 1146 | - $td->NORMALIZE_NEWLINES); | |
| 1147 | -} | |
| 1148 | - | |
| 1149 | -$td->runtest("bad json stream data (inline)", | |
| 1150 | - {$td->COMMAND => | |
| 1151 | - "qpdf --json=2 --test-json-schema" . | |
| 1152 | - " --json-stream-data=inline bad-data.pdf > a.json"}, | |
| 1153 | - {$td->FILE => "bad-data-json.out", $td->EXIT_STATUS => 3}, | |
| 1154 | - $td->NORMALIZE_NEWLINES); | |
| 1155 | -$td->runtest("check (inline)", | |
| 1156 | - {$td->FILE => "a.json"}, | |
| 1157 | - {$td->FILE => "json-bad-data-json-inline-v2.out"}, | |
| 1158 | - $td->NORMALIZE_NEWLINES); | |
| 1159 | -$td->runtest("bad json stream data (file)", | |
| 1160 | - {$td->COMMAND => | |
| 1161 | - "qpdf --json=2 --test-json-schema" . | |
| 1162 | - " --json-stream-data=file --json-stream-prefix=auto" . | |
| 1163 | - " bad-data.pdf > a.json"}, | |
| 1164 | - {$td->FILE => "bad-data-json.out", $td->EXIT_STATUS => 3}, | |
| 1165 | - $td->NORMALIZE_NEWLINES); | |
| 1166 | -$td->runtest("check (file)", | |
| 1167 | - {$td->FILE => "a.json"}, | |
| 1168 | - {$td->FILE => "json-bad-data-json-file-v2.out"}, | |
| 1169 | - $td->NORMALIZE_NEWLINES); | |
| 1170 | -$td->runtest("check stream (file)", | |
| 1171 | - {$td->FILE => "auto-4"}, | |
| 1172 | - {$td->FILE => "bad-data-4.out"}); | |
| 1173 | - | |
| 1174 | -foreach my $l (qw(none generalized specialized all)) | |
| 1175 | -{ | |
| 1176 | - if ($l ne 'all') | |
| 1177 | - { | |
| 1178 | - # We don't want a dependency on the exact value of the | |
| 1179 | - # uncompressed jpeg, which can differ depending on which jpeg | |
| 1180 | - # library is use. | |
| 1181 | - $td->runtest("image-streams json inline: $l", | |
| 1182 | - {$td->COMMAND => | |
| 1183 | - "qpdf image-streams-small.pdf --json=2" . | |
| 1184 | - " --decode-level=$l --json-stream-data=inline"}, | |
| 1185 | - {$td->FILE => "json-image-streams-$l-inline-v2.out", | |
| 1186 | - $td->EXIT_STATUS => 0}, | |
| 1187 | - $td->NORMALIZE_NEWLINES); | |
| 1188 | - } | |
| 1189 | - $td->runtest("image-streams json file: $l", | |
| 1190 | - {$td->COMMAND => | |
| 1191 | - "qpdf image-streams-small.pdf --json=2" . | |
| 1192 | - " --decode-level=$l --json-stream-data=file" . | |
| 1193 | - " --json-stream-prefix=auto --json-key=qpdf" . | |
| 1194 | - " --json-object=12 --json-object=16 --json-object=18"}, | |
| 1195 | - {$td->FILE => "json-image-streams-$l-file-v2.out", | |
| 1196 | - $td->EXIT_STATUS => 0}, | |
| 1197 | - $td->NORMALIZE_NEWLINES); | |
| 1198 | - # object 12: /FlateDecode | |
| 1199 | - # object 16: /DCTDecode | |
| 1200 | - # object 18: /RunLengthDecode | |
| 1201 | - my %exp_compression = ( | |
| 1202 | - '12' => {'none' => 1}, | |
| 1203 | - '16' => {'none' => 1, 'generalized' => 1, 'specialized' => 1}, | |
| 1204 | - '18' => {'none' => 1, 'generalized' => 1}, | |
| 1205 | - ); | |
| 1206 | - | |
| 1207 | - foreach my $obj (qw(12 16 18)) | |
| 1208 | - { | |
| 1209 | - my $compressed = (exists $exp_compression{$obj}{$l}); | |
| 1210 | - my $suf = $compressed ? "compressed" : "uncompressed"; | |
| 1211 | - if (($obj eq '16') && (! $compressed)) | |
| 1212 | - { | |
| 1213 | - # Rather than testing the uncompressed DCT, just make sure | |
| 1214 | - # it is different from the compressed DCT. | |
| 1215 | - my $same = (compare( | |
| 1216 | - "auto-$obj", | |
| 1217 | - "image-streams-small-$obj-compressed.out") ? | |
| 1218 | - "same" : "different"); | |
| 1219 | - $td->runtest("check stream data ($obj, $l)", | |
| 1220 | - {$td->STRING => $same}, | |
| 1221 | - {$td->STRING => "same"}); | |
| 1222 | - } | |
| 1223 | - else | |
| 1224 | - { | |
| 1225 | - $td->runtest("check stream data ($obj, $l)", | |
| 1226 | - {$td->FILE => "auto-$obj"}, | |
| 1227 | - {$td->FILE => "image-streams-small-$obj-$suf.out"}); | |
| 1228 | - } | |
| 1229 | - } | |
| 1230 | -} | |
| 1231 | - | |
| 1232 | -$td->runtest("use --to-json option", | |
| 1233 | - {$td->COMMAND => "qpdf --to-json image-streams-small.pdf"}, | |
| 1234 | - {$td->FILE => "image-streams-small-to-json.out", | |
| 1235 | - $td->EXIT_STATUS => 0}, | |
| 1236 | - $td->NORMALIZE_NEWLINES); | |
| 1237 | - | |
| 1238 | -show_ntests(); | |
| 1239 | -# ---------- | |
| 1240 | -$td->notify("--- Page API Tests ---"); | |
| 1241 | -$n_tests += 11; | |
| 1242 | - | |
| 1243 | -$td->runtest("basic page API", | |
| 1244 | - {$td->COMMAND => "test_driver 15 page_api_1.pdf"}, | |
| 1245 | - {$td->STRING => "test 15 done\n", $td->EXIT_STATUS => 0}, | |
| 1246 | - $td->NORMALIZE_NEWLINES); | |
| 1247 | -$td->runtest("check output", | |
| 1248 | - {$td->FILE => "a.pdf"}, | |
| 1249 | - {$td->FILE => "page_api_1-out.pdf"}); | |
| 1250 | -$td->runtest("manual page manipulation", | |
| 1251 | - {$td->COMMAND => "test_driver 16 page_api_1.pdf"}, | |
| 1252 | - {$td->STRING => "test 16 done\n", $td->EXIT_STATUS => 0}, | |
| 1253 | - $td->NORMALIZE_NEWLINES); | |
| 1254 | -$td->runtest("check output", | |
| 1255 | - {$td->FILE => "a.pdf"}, | |
| 1256 | - {$td->FILE => "page_api_1-out2.pdf"}); | |
| 1257 | -$td->runtest("duplicate page", | |
| 1258 | - {$td->COMMAND => "test_driver 17 page_api_2.pdf"}, | |
| 1259 | - {$td->FILE => "page_api_2.out", $td->EXIT_STATUS => 0}, | |
| 1260 | - $td->NORMALIZE_NEWLINES); | |
| 1261 | -$td->runtest("delete and re-add a page", | |
| 1262 | - {$td->COMMAND => "test_driver 18 page_api_1.pdf"}, | |
| 1263 | - {$td->STRING => "test 18 done\n", $td->EXIT_STATUS => 0}, | |
| 1264 | - $td->NORMALIZE_NEWLINES); | |
| 1265 | -$td->runtest("check output", | |
| 1266 | - {$td->FILE => "a.pdf"}, | |
| 1267 | - {$td->FILE => "page_api_1-out3.pdf"}); | |
| 1268 | -$td->runtest("duplicate page", | |
| 1269 | - {$td->COMMAND => "test_driver 19 page_api_1.pdf"}, | |
| 1270 | - {$td->FILE => "page_api_1.out", $td->EXIT_STATUS => 0}, | |
| 1271 | - $td->NORMALIZE_NEWLINES); | |
| 1272 | -$td->runtest("remove page we don't have", | |
| 1273 | - {$td->COMMAND => "test_driver 22 page_api_1.pdf"}, | |
| 1274 | - {$td->FILE => "page_api_1.out2", $td->EXIT_STATUS => 2}, | |
| 1275 | - $td->NORMALIZE_NEWLINES); | |
| 1276 | -$td->runtest("flatten rotation", | |
| 1277 | - {$td->COMMAND => "qpdf --static-id --qdf". | |
| 1278 | - " --no-original-object-ids" . | |
| 1279 | - " --flatten-rotation boxes.pdf a.pdf"}, | |
| 1280 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 1281 | - $td->NORMALIZE_NEWLINES); | |
| 1282 | -$td->runtest("check output", | |
| 1283 | - {$td->FILE => "a.pdf"}, | |
| 1284 | - {$td->FILE => "boxes-flattened.pdf"}); | |
| 1285 | -show_ntests(); | |
| 1286 | -# ---------- | |
| 1287 | -$td->notify("--- Files for specific bugs ---"); | |
| 1288 | -# The number is the github issue number in which the bug was reported. | |
| 1289 | -my @bug_tests = ( | |
| 1290 | - ["51", "resolve loop", 3], | |
| 1291 | - ["99", "object 0", 2], | |
| 1292 | - ["99b", "object 0", 2], | |
| 1293 | - ["100", "xref reconstruction loop", 2], | |
| 1294 | - ["101", "resolve for exception text", 2], | |
| 1295 | - ["117", "other infinite loop", 3], | |
| 1296 | - ["118", "other infinite loop", 2], | |
| 1297 | - ["119", "other infinite loop", 3], | |
| 1298 | - ["120", "other infinite loop", 3], | |
| 1299 | - ["106", "zlib data error", 3], | |
| 1300 | - ["141a", "/W entry size 0", 2], | |
| 1301 | - ["141b", "/W entry size 0", 2], | |
| 1302 | - ["143", "self-referential ostream", 3, "--preserve-unreferenced"], | |
| 1303 | - ["146", "very deeply nested array", 2], | |
| 1304 | - ["147", "previously caused memory error", 2], | |
| 1305 | - ["148", "free memory on bad flate", 2], | |
| 1306 | - ["149", "xref prev pointer loop", 3], | |
| 1307 | - ["150", "integer overflow", 2], | |
| 1308 | - ["202", "even more deeply nested dictionary", 2], | |
| 1309 | - ["263", "empty xref stream", 2], | |
| 1310 | - ["335a", "ozz-fuzz-12152", 2], | |
| 1311 | - ["335b", "ozz-fuzz-14845", 2], | |
| 1312 | - ["fuzz-16214", "stream in object stream", 3, "--preserve-unreferenced"], | |
| 1313 | - # When adding to this list, consider adding to CORPUS_FROM_TEST in | |
| 1314 | - # fuzz/CMakeLists.txt and updating the count in | |
| 1315 | - # fuzz/qtest/fuzz.test. | |
| 1316 | - ); | |
| 1317 | -$n_tests += scalar(@bug_tests); | |
| 1318 | -foreach my $d (@bug_tests) | |
| 1319 | -{ | |
| 1320 | - my ($n, $description, $exit_status, $xargs) = @$d; | |
| 1321 | - if (! defined $xargs) | |
| 1322 | - { | |
| 1323 | - $xargs = ""; | |
| 1324 | - } | |
| 1325 | - if (-f "issue-$n.obfuscated") | |
| 1326 | - { | |
| 1327 | - # Some of the PDF files in the test suite trigger anti-virus | |
| 1328 | - # warnings (MAL/PDFEx-H) and are quarantined or deleted by | |
| 1329 | - # some antivirus software. These files are not actually | |
| 1330 | - # infected files with malicious intent. They are present in | |
| 1331 | - # the test suite to ensure that qpdf does not crash when | |
| 1332 | - # process those files. Base64-encode them and pass them to | |
| 1333 | - # stdin to prevent anti-virus programs from messing up the | |
| 1334 | - # extracted sources. Search for "obfuscated" in test_driver.cc | |
| 1335 | - # for instructions on how to obfuscate input files. | |
| 1336 | - $td->runtest($description, | |
| 1337 | - {$td->COMMAND => "test_driver 45 issue-$n"}, | |
| 1338 | - {$td->FILE => "issue-$n.out", | |
| 1339 | - $td->EXIT_STATUS => $exit_status}, | |
| 1340 | - $td->NORMALIZE_NEWLINES); | |
| 1341 | - } | |
| 1342 | - else | |
| 1343 | - { | |
| 1344 | - my $base = (-f "issue-$n.pdf") ? "issue-$n" : "$n"; | |
| 1345 | - $td->runtest($description, | |
| 1346 | - {$td->COMMAND => "qpdf $xargs $base.pdf a.pdf"}, | |
| 1347 | - {$td->FILE => "$base.out", | |
| 1348 | - $td->EXIT_STATUS => $exit_status}, | |
| 1349 | - $td->NORMALIZE_NEWLINES); | |
| 1350 | - } | |
| 1351 | -} | |
| 1352 | -show_ntests(); | |
| 1353 | -# ---------- | |
| 1354 | -$td->notify("--- Positive /P in encryption dictionary ---"); | |
| 1355 | -$n_tests += 4; | |
| 1356 | - | |
| 1357 | -# Files have been seen where /P in the encryption dictionary was an | |
| 1358 | -# unsigned rather than a signed integer. To create | |
| 1359 | -# encrypted-positive-P.pdf, I temporarily modified QPDFWriter.cc to | |
| 1360 | -# introduce this error. | |
| 1361 | - | |
| 1362 | -$td->runtest("decrypt positive P", | |
| 1363 | - {$td->COMMAND => | |
| 1364 | - "qpdf --decrypt --static-id encrypted-positive-P.pdf a.pdf"}, | |
| 1365 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 1366 | -$td->runtest("check output", | |
| 1367 | - {$td->FILE => "a.pdf"}, | |
| 1368 | - {$td->FILE => "decrypted-positive-P.pdf"}); | |
| 1369 | -$td->runtest("copy encryption positive P", | |
| 1370 | - {$td->COMMAND => | |
| 1371 | - "qpdf --static-id --static-aes-iv" . | |
| 1372 | - " encrypted-positive-P.pdf a.pdf"}, | |
| 1373 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 1374 | -$td->runtest("check output", | |
| 1375 | - {$td->FILE => "a.pdf"}, | |
| 1376 | - {$td->FILE => "copied-positive-P.pdf"}); | |
| 1377 | - | |
| 1378 | -show_ntests(); | |
| 1379 | -# ---------- | |
| 1380 | -$td->notify("--- Library version ---"); | |
| 1381 | -$n_tests += 3; | |
| 1382 | - | |
| 1383 | -$td->runtest("qpdf version", | |
| 1384 | - {$td->COMMAND => "qpdf --version"}, | |
| 1385 | - {$td->REGEXP => ".*qpdf version \\S+\n.*", $td->EXIT_STATUS => 0}, | |
| 1386 | - $td->NORMALIZE_NEWLINES); | |
| 1387 | -$td->runtest("qpdf copyright contains version too", | |
| 1388 | - {$td->COMMAND => "qpdf --copyright"}, | |
| 1389 | - {$td->REGEXP => "(?s)qpdf version \\S+\n.*Apache.*", | |
| 1390 | - $td->EXIT_STATUS => 0}, | |
| 1391 | - $td->NORMALIZE_NEWLINES); | |
| 1392 | -$td->runtest("C API: qpdf version", | |
| 1393 | - {$td->COMMAND => "qpdf-ctest --version"}, | |
| 1394 | - {$td->REGEXP => "qpdf-ctest version \\S+\n", | |
| 1395 | - $td->EXIT_STATUS => 0}, | |
| 1396 | - $td->NORMALIZE_NEWLINES); | |
| 1397 | - | |
| 1398 | -show_ntests(); | |
| 1399 | -# ---------- | |
| 1400 | -$td->notify("--- Linearize pass1 file ---"); | |
| 1401 | -$n_tests += 3; | |
| 1402 | - | |
| 1403 | -$td->runtest("linearize pass 1 file", | |
| 1404 | - {$td->COMMAND => "qpdf --linearize --static-id" . | |
| 1405 | - " --linearize-pass1=b.pdf minimal.pdf a.pdf"}, | |
| 1406 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 1407 | -$td->runtest("check output", | |
| 1408 | - {$td->FILE => "a.pdf"}, | |
| 1409 | - {$td->FILE => "minimal-linearized.pdf"}); | |
| 1410 | -$td->runtest("check pass1 file", | |
| 1411 | - {$td->FILE => "b.pdf"}, | |
| 1412 | - {$td->FILE => "minimal-linearize-pass1.pdf"}); | |
| 1413 | - | |
| 1414 | -show_ntests(); | |
| 1415 | -# ---------- | |
| 1416 | -$td->notify("--- Inline Images ---"); | |
| 1417 | -$n_tests += 10; | |
| 1418 | - | |
| 1419 | -# The file large-inline-image.pdf is a hand-crafted file with several | |
| 1420 | -# inline images of various sizes including one that is two megabytes, | |
| 1421 | -# encoded in base85, and has a base85-encoding that contains EI | |
| 1422 | -# surrounded by delimiters several times. This exercises the EI | |
| 1423 | -# detection code added in qpdf 8.4. | |
| 1424 | - | |
| 1425 | -$td->runtest("complex inline image parsing", | |
| 1426 | - {$td->COMMAND => | |
| 1427 | - "qpdf --qdf --static-id large-inline-image.pdf a.pdf"}, | |
| 1428 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 1429 | - $td->NORMALIZE_NEWLINES); | |
| 1430 | -$td->runtest("check output", | |
| 1431 | - {$td->FILE => "a.pdf"}, | |
| 1432 | - {$td->FILE => "large-inline-image.qdf"}); | |
| 1433 | - | |
| 1434 | -$td->runtest("eof in inline image", | |
| 1435 | - {$td->COMMAND => | |
| 1436 | - "qpdf --qdf --static-id eof-in-inline-image.pdf a.pdf"}, | |
| 1437 | - {$td->FILE => "eof-inline-qdf.out", $td->EXIT_STATUS => 3}, | |
| 1438 | - $td->NORMALIZE_NEWLINES); | |
| 1439 | -$td->runtest("check output", | |
| 1440 | - {$td->FILE => "a.pdf"}, | |
| 1441 | - {$td->FILE => "eof-in-inline-image.qdf"}); | |
| 1442 | -$td->runtest("externalize eof in inline image", | |
| 1443 | - {$td->COMMAND => | |
| 1444 | - "qpdf --qdf --externalize-inline-images" . | |
| 1445 | - " --static-id eof-in-inline-image.pdf a.pdf"}, | |
| 1446 | - {$td->FILE => "eof-inline-qdf.out", $td->EXIT_STATUS => 3}, | |
| 1447 | - $td->NORMALIZE_NEWLINES); | |
| 1448 | -$td->runtest("check output", | |
| 1449 | - {$td->FILE => "a.pdf"}, | |
| 1450 | - {$td->FILE => "eof-in-inline-image-ii.qdf"}); | |
| 1451 | -$td->runtest("externalize damaged image", | |
| 1452 | - {$td->COMMAND => | |
| 1453 | - "qpdf --externalize-inline-images" . | |
| 1454 | - " --compress-streams=n --static-id" . | |
| 1455 | - " damaged-inline-image.pdf a.pdf"}, | |
| 1456 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 1457 | - $td->NORMALIZE_NEWLINES); | |
| 1458 | -$td->runtest("check output", | |
| 1459 | - {$td->FILE => "a.pdf"}, | |
| 1460 | - {$td->FILE => "damaged-inline-image-out.pdf"}); | |
| 1461 | -$td->runtest("named colorspace", | |
| 1462 | - {$td->COMMAND => | |
| 1463 | - "qpdf --static-id --externalize-inline-images" . | |
| 1464 | - " --ii-min-bytes=0 inline-image-colorspace-lookup.pdf a.pdf"}, | |
| 1465 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 1466 | - $td->NORMALIZE_NEWLINES); | |
| 1467 | -$td->runtest("check output", | |
| 1468 | - {$td->FILE => "a.pdf"}, | |
| 1469 | - {$td->FILE => "inline-image-colorspace-lookup-out.pdf"}); | |
| 1470 | - | |
| 1471 | - | |
| 1472 | -my @eii_tests = ( | |
| 1473 | - ['inline-images', 80], | |
| 1474 | - ['large-inline-image', 1024], | |
| 1475 | - ['nested-form-xobjects-inline-images', 20], | |
| 1476 | - ); | |
| 1477 | -$n_tests += 4 * scalar(@eii_tests); | |
| 1478 | -$n_compare_pdfs += 2 * scalar(@eii_tests); | |
| 1479 | - | |
| 1480 | -foreach my $d (@eii_tests) | |
| 1481 | -{ | |
| 1482 | - my ($file, $threshold) = @$d; | |
| 1483 | - $td->runtest("inline image $file (all)", | |
| 1484 | - {$td->COMMAND => | |
| 1485 | - "qpdf --qdf --static-id --externalize-inline-images" . | |
| 1486 | - " --ii-min-bytes=0 $file.pdf a.pdf"}, | |
| 1487 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 1488 | - $td->NORMALIZE_NEWLINES); | |
| 1489 | - $td->runtest("check output", | |
| 1490 | - {$td->FILE => "a.pdf"}, | |
| 1491 | - {$td->FILE => "$file-ii-all.pdf"}); | |
| 1492 | - compare_pdfs("$file.pdf", "a.pdf"); | |
| 1493 | - | |
| 1494 | - $td->runtest("inline image $file (some)", | |
| 1495 | - {$td->COMMAND => | |
| 1496 | - "qpdf --qdf --static-id --externalize-inline-images" . | |
| 1497 | - " --ii-min-bytes=$threshold $file.pdf a.pdf"}, | |
| 1498 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 1499 | - $td->NORMALIZE_NEWLINES); | |
| 1500 | - $td->runtest("check output", | |
| 1501 | - {$td->FILE => "a.pdf"}, | |
| 1502 | - {$td->FILE => "$file-ii-some.pdf"}); | |
| 1503 | - compare_pdfs("$file.pdf", "a.pdf"); | |
| 1504 | -} | |
| 1505 | - | |
| 1506 | -show_ntests(); | |
| 1507 | -# ---------- | |
| 1508 | -$td->notify("--- Tokenizer ---"); | |
| 1509 | -$n_tests += 4; | |
| 1510 | - | |
| 1511 | -$td->runtest("tokenizer with no ignorable", | |
| 1512 | - {$td->COMMAND => "test_tokenizer -no-ignorable tokens.pdf"}, | |
| 1513 | - {$td->FILE => "tokens-no-ignorable.out", $td->EXIT_STATUS => 0}, | |
| 1514 | - $td->NORMALIZE_NEWLINES); | |
| 1515 | - | |
| 1516 | -$td->runtest("tokenizer", | |
| 1517 | - {$td->COMMAND => "test_tokenizer tokens.pdf"}, | |
| 1518 | - {$td->FILE => "tokens.out", $td->EXIT_STATUS => 0}, | |
| 1519 | - $td->NORMALIZE_NEWLINES); | |
| 1520 | - | |
| 1521 | -$td->runtest("tokenizer with max_len", | |
| 1522 | - {$td->COMMAND => "test_tokenizer -maxlen 50 tokens.pdf"}, | |
| 1523 | - {$td->FILE => "tokens-maxlen.out", $td->EXIT_STATUS => 0}, | |
| 1524 | - $td->NORMALIZE_NEWLINES); | |
| 1525 | - | |
| 1526 | -$td->runtest("ignore bad token", | |
| 1527 | - {$td->COMMAND => | |
| 1528 | - "qpdf --show-xref bad-token-startxref.pdf"}, | |
| 1529 | - {$td->FILE => "bad-token-startxref.out", | |
| 1530 | - $td->EXIT_STATUS => 0}, | |
| 1531 | - $td->NORMALIZE_NEWLINES); | |
| 1532 | - | |
| 1533 | -show_ntests(); | |
| 1534 | -# ---------- | |
| 1535 | -$td->notify("--- Numbers and strings ---"); | |
| 1536 | -$n_tests += 3; | |
| 1537 | - | |
| 1538 | -foreach (my $i = 1; $i <= 3; ++$i) | |
| 1539 | -{ | |
| 1540 | - $td->runtest("numbers and strings", | |
| 1541 | - {$td->COMMAND => "test_driver 5 numeric-and-string-$i.pdf"}, | |
| 1542 | - {$td->FILE => "numeric-and-string-$i.out", | |
| 1543 | - $td->EXIT_STATUS => 0}, | |
| 1544 | - $td->NORMALIZE_NEWLINES); | |
| 1545 | -} | |
| 1546 | - | |
| 1547 | -show_ntests(); | |
| 1548 | -# ---------- | |
| 1549 | -$td->notify("--- Miscellaneous QPDFObjectHandle API ---"); | |
| 1550 | -$n_tests += 2; | |
| 1551 | - | |
| 1552 | -$td->runtest("dictionary keys", | |
| 1553 | - {$td->COMMAND => "test_driver 87 - -"}, | |
| 1554 | - {$td->STRING => "test 87 done\n", $td->EXIT_STATUS => 0}, | |
| 1555 | - $td->NORMALIZE_NEWLINES); | |
| 1556 | -$td->runtest("fluent interfaces", | |
| 1557 | - {$td->COMMAND => "test_driver 88 minimal.pdf -"}, | |
| 1558 | - {$td->FILE => "test88.out", $td->EXIT_STATUS => 0}, | |
| 1559 | - $td->NORMALIZE_NEWLINES); | |
| 1560 | - | |
| 1561 | -show_ntests(); | |
| 1562 | -# ---------- | |
| 1563 | -$td->notify("--- Stream data ---"); | |
| 1564 | -$n_tests += 2; | |
| 1565 | - | |
| 1566 | -$td->runtest("get stream data", | |
| 1567 | - {$td->COMMAND => "test_driver 11 stream-data.pdf"}, | |
| 1568 | - {$td->FILE => "test11.out", $td->EXIT_STATUS => 0}, | |
| 1569 | - $td->NORMALIZE_NEWLINES); | |
| 1570 | -$td->runtest("get stream data fails on jpeg", | |
| 1571 | - {$td->COMMAND => "test_driver 68 jpeg-qstream.pdf"}, | |
| 1572 | - {$td->FILE => "test68.out", $td->EXIT_STATUS => 0}, | |
| 1573 | - $td->NORMALIZE_NEWLINES); | |
| 1574 | - | |
| 1575 | -show_ntests(); | |
| 1576 | -# ---------- | |
| 1577 | -$td->notify("--- Decode parameter problems ---"); | |
| 1578 | -$n_tests += 6; | |
| 1579 | - | |
| 1580 | -# Make sure we ignore decode parameters that we don't understand | |
| 1581 | -$td->runtest("unknown decode parameters", | |
| 1582 | - {$td->COMMAND => "qpdf --check fax-decode-parms.pdf"}, | |
| 1583 | - {$td->FILE => "fax-decode-parms.out", | |
| 1584 | - $td->EXIT_STATUS => 0}, | |
| 1585 | - $td->NORMALIZE_NEWLINES); | |
| 1586 | - | |
| 1587 | -$td->runtest("ignore broken decode parms with no filters", | |
| 1588 | - {$td->COMMAND => "qpdf --check broken-decode-parms-no-filter.pdf"}, | |
| 1589 | - {$td->FILE => "broken-decode-parms-no-filter.out", | |
| 1590 | - $td->EXIT_STATUS => 0}, | |
| 1591 | - $td->NORMALIZE_NEWLINES); | |
| 1592 | - | |
| 1593 | -$td->runtest("stream with indirect decode parms", | |
| 1594 | - {$td->COMMAND => | |
| 1595 | - "qpdf --static-id indirect-decode-parms.pdf a.pdf"}, | |
| 1596 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 1597 | -$td->runtest("check file", | |
| 1598 | - {$td->FILE => "a.pdf"}, | |
| 1599 | - {$td->FILE => "indirect-decode-parms-out.pdf"}); | |
| 1600 | - | |
| 1601 | -$td->runtest("decode parameters empty list", | |
| 1602 | - {$td->COMMAND => "qpdf --static-id empty-decode-parms.pdf a.pdf"}, | |
| 1603 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 1604 | -$td->runtest("check file", | |
| 1605 | - {$td->FILE => "a.pdf"}, | |
| 1606 | - {$td->FILE => "empty-decode-parms-out.pdf"}); | |
| 1607 | - | |
| 1608 | -show_ntests(); | |
| 1609 | -# ---------- | |
| 1610 | -$td->notify("--- Cross reference streams ---"); | |
| 1611 | -$n_tests += 3; | |
| 1612 | - | |
| 1613 | -# Handle xref stream with more entries than reported (bug 2872265) | |
| 1614 | -$td->runtest("xref with short size", | |
| 1615 | - {$td->COMMAND => "qpdf --show-xref xref-with-short-size.pdf"}, | |
| 1616 | - {$td->FILE => "xref-with-short-size.out", | |
| 1617 | - $td->EXIT_STATUS => 3}, | |
| 1618 | - $td->NORMALIZE_NEWLINES); | |
| 1619 | -$td->runtest("recover xref with short size", | |
| 1620 | - {$td->COMMAND => "qpdf xref-with-short-size.pdf a.pdf"}, | |
| 1621 | - {$td->FILE => "xref-with-short-size-recover.out", | |
| 1622 | - $td->EXIT_STATUS => 3}, | |
| 1623 | - $td->NORMALIZE_NEWLINES); | |
| 1624 | -$td->runtest("show new xref stream", | |
| 1625 | - {$td->COMMAND => "qpdf --show-xref a.pdf"}, | |
| 1626 | - {$td->FILE => "xref-with-short-size-new.out", | |
| 1627 | - $td->EXIT_STATUS => 0}, | |
| 1628 | - $td->NORMALIZE_NEWLINES); | |
| 1629 | - | |
| 1630 | -show_ntests(); | |
| 1631 | -# ---------- | |
| 1632 | -$td->notify("--- Multiple levels of indirection ---"); | |
| 1633 | -$n_tests += 2; | |
| 1634 | - | |
| 1635 | -# Handle file with object stream containing an unreferenced object | |
| 1636 | -# that in turn contains an indirect scalar (bug 2974522). | |
| 1637 | -$td->runtest("unreferenced indirect scalar", | |
| 1638 | - {$td->COMMAND => | |
| 1639 | - "qpdf --qdf --static-id --preserve-unreferenced" . | |
| 1640 | - " --object-streams=preserve" . | |
| 1641 | - " unreferenced-indirect-scalar.pdf a.qdf"}, | |
| 1642 | - {$td->STRING => "", | |
| 1643 | - $td->EXIT_STATUS => 0}, | |
| 1644 | - $td->NORMALIZE_NEWLINES); | |
| 1645 | -$td->runtest("check output", | |
| 1646 | - {$td->FILE => "a.qdf"}, | |
| 1647 | - {$td->FILE => "unreferenced-indirect-scalar.out"}); | |
| 1648 | - | |
| 1649 | -show_ntests(); | |
| 1650 | -# ---------- | |
| 1651 | -$td->notify("--- ID and Encryption Parameter Issues ---"); | |
| 1652 | -$n_tests += 13; | |
| 1653 | - | |
| 1654 | -# Encrypt files whose /ID strings are other than 32 bytes long (bug | |
| 1655 | -# 2991412). Also linearize these files, which was reported in a | |
| 1656 | -# separate bug by email. | |
| 1657 | -foreach my $file (qw(short-id long-id)) | |
| 1658 | -{ | |
| 1659 | - $td->runtest("encrypt $file.pdf", | |
| 1660 | - {$td->COMMAND => | |
| 1661 | - "qpdf --allow-weak-crypto". | |
| 1662 | - " --encrypt '' pass 40 -- $file.pdf a.pdf"}, | |
| 1663 | - {$td->STRING => "", | |
| 1664 | - $td->EXIT_STATUS => 0}, | |
| 1665 | - $td->NORMALIZE_NEWLINES); | |
| 1666 | - | |
| 1667 | - $td->runtest("check $file.pdf", | |
| 1668 | - {$td->COMMAND => "qpdf --check --show-encryption-key a.pdf"}, | |
| 1669 | - {$td->FILE => "$file-check.out", | |
| 1670 | - $td->EXIT_STATUS => 0}, | |
| 1671 | - $td->NORMALIZE_NEWLINES); | |
| 1672 | - | |
| 1673 | - $td->runtest("linearize $file.pdf", | |
| 1674 | - {$td->COMMAND => | |
| 1675 | - "qpdf --deterministic-id --linearize $file.pdf a.pdf"}, | |
| 1676 | - {$td->STRING => "", | |
| 1677 | - $td->EXIT_STATUS => 0}, | |
| 1678 | - $td->NORMALIZE_NEWLINES); | |
| 1679 | - | |
| 1680 | - $td->runtest("check output", | |
| 1681 | - {$td->FILE => "a.pdf"}, | |
| 1682 | - {$td->FILE => "$file-linearized.pdf"}); | |
| 1683 | - | |
| 1684 | - $td->runtest("check $file.pdf", | |
| 1685 | - {$td->COMMAND => "qpdf --check a.pdf"}, | |
| 1686 | - {$td->FILE => "$file-linearized-check.out", | |
| 1687 | - $td->EXIT_STATUS => 0}, | |
| 1688 | - $td->NORMALIZE_NEWLINES); | |
| 1689 | -} | |
| 1690 | - | |
| 1691 | -# A user provided a file that was missing /ID in its trailer even | |
| 1692 | -# though it is encrypted and also has a space instead of a newline | |
| 1693 | -# after its xref keyword. This file has those same properties. | |
| 1694 | -$td->runtest("check broken file", | |
| 1695 | - {$td->COMMAND => "qpdf --check invalid-id-xref.pdf"}, | |
| 1696 | - {$td->FILE => "invalid-id-xref.out", $td->EXIT_STATUS => 3}, | |
| 1697 | - $td->NORMALIZE_NEWLINES); | |
| 1698 | - | |
| 1699 | -# A file was emailed privately with issue 96. short-O-U.pdf was | |
| 1700 | -# created by copying encryption parameters from that file. It exhibits | |
| 1701 | -# the same behavior as the original file. | |
| 1702 | -$td->runtest("short /O or /U", | |
| 1703 | - {$td->COMMAND => | |
| 1704 | - "qpdf --password=19723102477 --check short-O-U.pdf"}, | |
| 1705 | - {$td->FILE => "short-O-U.out", | |
| 1706 | - $td->EXIT_STATUS => 0}, | |
| 1707 | - $td->NORMALIZE_NEWLINES); | |
| 1708 | - | |
| 1709 | -# A file was sent to me privately as part of issue 212. This file was | |
| 1710 | -# encrypted and had /R=3 and /V=1 and was using a 40-bit key. qpdf was | |
| 1711 | -# failing to work properly on files with /R=3 and 40-bit keys. The | |
| 1712 | -# test file is not this private file, but the encryption parameters | |
| 1713 | -# were copied from it. Like the bug file, qpdf < 8.1 can't decrypt it. | |
| 1714 | -$td->runtest("/R 3 with 40-bit key", | |
| 1715 | - {$td->COMMAND => | |
| 1716 | - "qpdf --password=623 --check --show-encryption-key" . | |
| 1717 | - " encrypted-40-bit-R3.pdf"}, | |
| 1718 | - {$td->FILE => "encrypted-40-bit-R3.out", | |
| 1719 | - $td->EXIT_STATUS => 0}, | |
| 1720 | - $td->NORMALIZE_NEWLINES); | |
| 1721 | - | |
| 1722 | -show_ntests(); | |
| 1723 | -# ---------- | |
| 1724 | -$td->notify("--- Min/force version ---"); | |
| 1725 | -$n_tests += 7; | |
| 1726 | - | |
| 1727 | -# Min/Force version | |
| 1728 | -$td->runtest("set min version", | |
| 1729 | - {$td->COMMAND => "qpdf --verbose --min-version=1.6 good1.pdf a.pdf"}, | |
| 1730 | - {$td->STRING => "qpdf: wrote file a.pdf\n", | |
| 1731 | - $td->EXIT_STATUS => 0}, | |
| 1732 | - $td->NORMALIZE_NEWLINES); | |
| 1733 | -$td->runtest("check version", | |
| 1734 | - {$td->COMMAND => "qpdf --check a.pdf"}, | |
| 1735 | - {$td->FILE => "min-version.out", | |
| 1736 | - $td->EXIT_STATUS => 0}, | |
| 1737 | - $td->NORMALIZE_NEWLINES); | |
| 1738 | -$td->runtest("force version", | |
| 1739 | - {$td->COMMAND => "qpdf --force-version=1.4 a.pdf b.pdf"}, | |
| 1740 | - {$td->STRING => "", | |
| 1741 | - $td->EXIT_STATUS => 0}, | |
| 1742 | - $td->NORMALIZE_NEWLINES); | |
| 1743 | -$td->runtest("check version", | |
| 1744 | - {$td->COMMAND => "qpdf --check b.pdf"}, | |
| 1745 | - {$td->FILE => "forced-version.out", | |
| 1746 | - $td->EXIT_STATUS => 0}, | |
| 1747 | - $td->NORMALIZE_NEWLINES); | |
| 1748 | -unlink "a.pdf", "b.pdf" or die; | |
| 1749 | -$td->runtest("C API: min/force versions", | |
| 1750 | - {$td->COMMAND => "qpdf-ctest 14 object-stream.pdf '' a.pdf b.pdf"}, | |
| 1751 | - {$td->STRING => "C test 14 done\n", | |
| 1752 | - $td->EXIT_STATUS => 0}, | |
| 1753 | - $td->NORMALIZE_NEWLINES); | |
| 1754 | -$td->runtest("C check version 1", | |
| 1755 | - {$td->COMMAND => "qpdf-ctest 1 a.pdf '' ''"}, | |
| 1756 | - {$td->FILE => "c-min-version.out", | |
| 1757 | - $td->EXIT_STATUS => 0}, | |
| 1758 | - $td->NORMALIZE_NEWLINES); | |
| 1759 | -$td->runtest("C check version 2", | |
| 1760 | - {$td->COMMAND => "qpdf --check b.pdf"}, | |
| 1761 | - {$td->FILE => "forced-version.out", | |
| 1762 | - $td->EXIT_STATUS => 0}, | |
| 1763 | - $td->NORMALIZE_NEWLINES); | |
| 1764 | - | |
| 1765 | -show_ntests(); | |
| 1766 | -# ---------- | |
| 1767 | -$td->notify("--- Filter abbreviations ---"); | |
| 1768 | -$n_tests += 2; | |
| 1769 | - | |
| 1770 | -# Stream filter abbreviations from table H.1 | |
| 1771 | -$td->runtest("stream filter abbreviations", | |
| 1772 | - {$td->COMMAND => "qpdf --static-id filter-abbreviation.pdf a.pdf"}, | |
| 1773 | - {$td->STRING => "", | |
| 1774 | - $td->EXIT_STATUS => 0}, | |
| 1775 | - $td->NORMALIZE_NEWLINES); | |
| 1776 | -$td->runtest("check output", | |
| 1777 | - {$td->FILE => "a.pdf"}, | |
| 1778 | - {$td->FILE => "filter-abbreviation.out"}); | |
| 1779 | - | |
| 1780 | -show_ntests(); | |
| 1781 | -# ---------- | |
| 1782 | -$td->notify("--- Disable filter on write ---"); | |
| 1783 | -$n_tests += 2; | |
| 1784 | - | |
| 1785 | -$td->runtest("no filter on write", | |
| 1786 | - {$td->COMMAND => "test_driver 70 filter-on-write.pdf"}, | |
| 1787 | - {$td->STRING => "test 70 done\n", $td->EXIT_STATUS => 0}, | |
| 1788 | - $td->NORMALIZE_NEWLINES); | |
| 1789 | -$td->runtest("check output", | |
| 1790 | - {$td->FILE => "a.pdf"}, | |
| 1791 | - {$td->FILE => "filter-on-write-out.pdf"}); | |
| 1792 | - | |
| 1793 | -show_ntests(); | |
| 1794 | -# ---------- | |
| 1795 | -$td->notify("--- Invalid objects ---"); | |
| 1796 | -$n_tests += 3; | |
| 1797 | - | |
| 1798 | -$td->runtest("closed input source", | |
| 1799 | - {$td->COMMAND => "test_driver 73 minimal.pdf"}, | |
| 1800 | - {$td->FILE => "test73.out", | |
| 1801 | - $td->EXIT_STATUS => 2}, | |
| 1802 | - $td->NORMALIZE_NEWLINES); | |
| 1803 | - | |
| 1804 | -$td->runtest("empty object", | |
| 1805 | - {$td->COMMAND => "qpdf -show-object=7,0 empty-object.pdf"}, | |
| 1806 | - {$td->FILE => "empty-object.out", | |
| 1807 | - $td->EXIT_STATUS => 3}, | |
| 1808 | - $td->NORMALIZE_NEWLINES); | |
| 1809 | - | |
| 1810 | -$td->runtest("object with zero offset", | |
| 1811 | - {$td->COMMAND => "qpdf --check zero-offset.pdf"}, | |
| 1812 | - {$td->FILE => "zero-offset.out", $td->EXIT_STATUS => 3}, | |
| 1813 | - $td->NORMALIZE_NEWLINES); | |
| 1814 | - | |
| 1815 | -show_ntests(); | |
| 1816 | -# ---------- | |
| 1817 | -$td->notify("--- Error/output redirection ---"); | |
| 1818 | -$n_tests += 2; | |
| 1819 | - | |
| 1820 | -$td->runtest("error/output redirection to null", | |
| 1821 | - {$td->COMMAND => "test_driver 12 linearized-and-warnings.pdf"}, | |
| 1822 | - {$td->FILE => "linearized-and-warnings-1.out", | |
| 1823 | - $td->EXIT_STATUS => 0}, | |
| 1824 | - $td->NORMALIZE_NEWLINES); | |
| 1825 | - | |
| 1826 | -$td->runtest("error/output redirection to strings", | |
| 1827 | - {$td->COMMAND => "test_driver 13 linearized-and-warnings.pdf"}, | |
| 1828 | - {$td->FILE => "linearized-and-warnings-2.out", | |
| 1829 | - $td->EXIT_STATUS => 0}, | |
| 1830 | - $td->NORMALIZE_NEWLINES); | |
| 1831 | - | |
| 1832 | -show_ntests(); | |
| 1833 | -# ---------- | |
| 1834 | -$td->notify("--- Line terminators for stream ---"); | |
| 1835 | -$n_tests += 2; | |
| 1836 | - | |
| 1837 | -$td->runtest("odd terminators for stream keyword", | |
| 1838 | - {$td->COMMAND => | |
| 1839 | - "qpdf --qdf --static-id" . | |
| 1840 | - " stream-line-enders.pdf a.qdf"}, | |
| 1841 | - {$td->FILE => "stream-line-enders.out", | |
| 1842 | - $td->EXIT_STATUS => 3}, | |
| 1843 | - $td->NORMALIZE_NEWLINES); | |
| 1844 | -$td->runtest("check output", | |
| 1845 | - {$td->FILE => "a.qdf"}, | |
| 1846 | - {$td->FILE => "stream-line-enders.qdf"}); | |
| 1847 | - | |
| 1848 | -show_ntests(); | |
| 1849 | -# ---------- | |
| 1850 | -$td->notify("--- Swap and replace ---"); | |
| 1851 | -$n_tests += 3; | |
| 1852 | - | |
| 1853 | -$td->runtest("swap and replace", | |
| 1854 | - {$td->COMMAND => "test_driver 14 test14-in.pdf"}, | |
| 1855 | - {$td->FILE => "test14.out", | |
| 1856 | - $td->EXIT_STATUS => 0}, | |
| 1857 | - $td->NORMALIZE_NEWLINES); | |
| 1858 | -$td->runtest("check output", | |
| 1859 | - {$td->FILE => "a.pdf"}, | |
| 1860 | - {$td->FILE => "test14-out.pdf"}); | |
| 1861 | - | |
| 1862 | -# Most of the test suite uses static or deterministic ID. This test | |
| 1863 | -# case exercises regular ID generation. Test 14 also exercises writing | |
| 1864 | -# to memory without static ID. | |
| 1865 | -$td->runtest("check non-static ID version", | |
| 1866 | - {$td->COMMAND => "sh ./diff-ignore-ID-version a.pdf b.pdf"}, | |
| 1867 | - {$td->STRING => "okay\n", $td->EXIT_STATUS => 0}, | |
| 1868 | - $td->NORMALIZE_NEWLINES); | |
| 1869 | - | |
| 1870 | -show_ntests(); | |
| 1871 | -# ---------- | |
| 1872 | -$td->notify("--- Key functions, C API ---"); | |
| 1873 | -$n_tests += 4; | |
| 1874 | - | |
| 1875 | -$td->runtest("C API info key functions", | |
| 1876 | - {$td->COMMAND => "qpdf-ctest 16 minimal.pdf '' a.pdf"}, | |
| 1877 | - {$td->FILE => "c-info1.out", | |
| 1878 | - $td->EXIT_STATUS => 0}, | |
| 1879 | - $td->NORMALIZE_NEWLINES); | |
| 1880 | -$td->runtest("check output", | |
| 1881 | - {$td->FILE => "a.pdf"}, | |
| 1882 | - {$td->FILE => "c-info-out.pdf"}); | |
| 1883 | -unlink "a.pdf" or die; | |
| 1884 | - | |
| 1885 | -$td->runtest("C API info key functions", | |
| 1886 | - {$td->COMMAND => "qpdf-ctest 16 c-info2-in.pdf '' a.pdf"}, | |
| 1887 | - {$td->FILE => "c-info2.out", | |
| 1888 | - $td->EXIT_STATUS => 0}, | |
| 1889 | - $td->NORMALIZE_NEWLINES); | |
| 1890 | -$td->runtest("check output", | |
| 1891 | - {$td->FILE => "a.pdf"}, | |
| 1892 | - {$td->FILE => "c-info-out.pdf"}); | |
| 1893 | -unlink "a.pdf" or die; | |
| 1894 | - | |
| 1895 | -show_ntests(); | |
| 1896 | -# ---------- | |
| 1897 | -$td->notify("--- Object copying ---"); | |
| 1898 | -$n_tests += 9; | |
| 1899 | - | |
| 1900 | -$td->runtest("shallow copy an array", | |
| 1901 | - {$td->COMMAND => "test_driver 20 shallow_array.pdf"}, | |
| 1902 | - {$td->STRING => "test 20 done\n", $td->EXIT_STATUS => 0}, | |
| 1903 | - $td->NORMALIZE_NEWLINES); | |
| 1904 | -$td->runtest("check output", | |
| 1905 | - {$td->FILE => "a.pdf"}, | |
| 1906 | - {$td->FILE => "shallow_array-out.pdf"}); | |
| 1907 | -$td->runtest("shallow copy a stream", | |
| 1908 | - {$td->COMMAND => "test_driver 21 shallow_array.pdf"}, | |
| 1909 | - {$td->FILE => "shallow_stream.out", $td->EXIT_STATUS => 2}, | |
| 1910 | - $td->NORMALIZE_NEWLINES); | |
| 1911 | -$td->runtest("warn for unknown key in Pages", | |
| 1912 | - {$td->COMMAND => "test_driver 23 lin-special.pdf"}, | |
| 1913 | - {$td->FILE => "pages-warning.out", $td->EXIT_STATUS => 0}, | |
| 1914 | - $td->NORMALIZE_NEWLINES); | |
| 1915 | -$td->runtest("reserved objects", | |
| 1916 | - {$td->COMMAND => "test_driver 24 minimal.pdf"}, | |
| 1917 | - {$td->FILE => "reserved-objects.out", $td->EXIT_STATUS => 0}, | |
| 1918 | - $td->NORMALIZE_NEWLINES); | |
| 1919 | -$td->runtest("check output", | |
| 1920 | - {$td->FILE => "a.pdf"}, | |
| 1921 | - {$td->FILE => "reserved-objects.pdf"}); | |
| 1922 | -$td->runtest("detect foreign object in write", | |
| 1923 | - {$td->COMMAND => "test_driver 29" . | |
| 1924 | - " copy-foreign-objects-in.pdf minimal.pdf"}, | |
| 1925 | - {$td->FILE => "foreign-in-write.out", $td->EXIT_STATUS => 0}, | |
| 1926 | - $td->NORMALIZE_NEWLINES); | |
| 1927 | -$td->runtest("copy a stream", | |
| 1928 | - {$td->COMMAND => "test_driver 79 minimal.pdf"}, | |
| 1929 | - {$td->STRING => "test 79 done\n", $td->EXIT_STATUS => 0}, | |
| 1930 | - $td->NORMALIZE_NEWLINES); | |
| 1931 | -$td->runtest("check output", | |
| 1932 | - {$td->FILE => "a.pdf"}, | |
| 1933 | - {$td->FILE => "test79.pdf"}); | |
| 1934 | - | |
| 1935 | -show_ntests(); | |
| 1936 | -# ---------- | |
| 1937 | -$td->notify("--- Merge Dictionary ---"); | |
| 1938 | -$n_tests += 3; | |
| 1939 | - | |
| 1940 | -$td->runtest("merge dictionary", | |
| 1941 | - {$td->COMMAND => "test_driver 50 merge-dict.pdf"}, | |
| 1942 | - {$td->FILE => "merge-dict.out", $td->EXIT_STATUS => 0}, | |
| 1943 | - $td->NORMALIZE_NEWLINES); | |
| 1944 | -$td->runtest("unique resource name", | |
| 1945 | - {$td->COMMAND => "test_driver 60 minimal.pdf"}, | |
| 1946 | - {$td->FILE => "test60.out", $td->EXIT_STATUS => 0}, | |
| 1947 | - $td->NORMALIZE_NEWLINES); | |
| 1948 | -$td->runtest("check output", | |
| 1949 | - {$td->FILE => "a.pdf"}, | |
| 1950 | - {$td->FILE => "unique-resources.pdf"}); | |
| 1951 | - | |
| 1952 | -show_ntests(); | |
| 1953 | -# ---------- | |
| 1954 | -$td->notify("--- Parsing ---"); | |
| 1955 | -$n_tests += 17; | |
| 1956 | - | |
| 1957 | -$td->runtest("parse objects from string", | |
| 1958 | - {$td->COMMAND => "test_driver 31 minimal.pdf"}, # file not used | |
| 1959 | - {$td->FILE => "parse-object.out", $td->EXIT_STATUS => 0}, | |
| 1960 | - $td->NORMALIZE_NEWLINES); | |
| 1961 | -$td->runtest("EOF terminating literal tokens", | |
| 1962 | - {$td->COMMAND => "qpdf --check eof-terminates-literal.pdf"}, | |
| 1963 | - {$td->FILE => "eof-terminates-literal.out", $td->EXIT_STATUS => 0}, | |
| 1964 | - $td->NORMALIZE_NEWLINES); | |
| 1965 | -$td->runtest("EOF reading token", | |
| 1966 | - {$td->COMMAND => "qpdf --check eof-reading-token.pdf"}, | |
| 1967 | - {$td->FILE => "eof-reading-token.out", $td->EXIT_STATUS => 3}, | |
| 1968 | - $td->NORMALIZE_NEWLINES); | |
| 1969 | -$td->runtest("extra header text", | |
| 1970 | - {$td->COMMAND => "test_driver 32 minimal.pdf"}, | |
| 1971 | - {$td->FILE => "test-32.out", $td->EXIT_STATUS => 0}, | |
| 1972 | - $td->NORMALIZE_NEWLINES); | |
| 1973 | -$td->runtest("check output", | |
| 1974 | - {$td->FILE => "a.pdf"}, | |
| 1975 | - {$td->FILE => "extra-header-no-newline.pdf"}); | |
| 1976 | -$td->runtest("check output", | |
| 1977 | - {$td->FILE => "b.pdf"}, | |
| 1978 | - {$td->FILE => "extra-header-lin-no-newline.pdf"}); | |
| 1979 | -$td->runtest("check output", | |
| 1980 | - {$td->FILE => "c.pdf"}, | |
| 1981 | - {$td->FILE => "extra-header-newline.pdf"}); | |
| 1982 | -$td->runtest("check output", | |
| 1983 | - {$td->FILE => "d.pdf"}, | |
| 1984 | - {$td->FILE => "extra-header-lin-newline.pdf"}); | |
| 1985 | - | |
| 1986 | -# leading-junk also has a space instead of a newline after xref | |
| 1987 | -$td->runtest("check file with leading junk", | |
| 1988 | - {$td->COMMAND => "qpdf --check leading-junk.pdf"}, | |
| 1989 | - {$td->FILE => "leading-junk.out", $td->EXIT_STATUS => 0}, | |
| 1990 | - $td->NORMALIZE_NEWLINES); | |
| 1991 | -$td->runtest("EOF inside inline image", | |
| 1992 | - {$td->COMMAND => "test_driver 37 eof-in-inline-image.pdf"}, | |
| 1993 | - {$td->FILE => "eof-in-inline-image.out", | |
| 1994 | - $td->EXIT_STATUS => 0}, | |
| 1995 | - $td->NORMALIZE_NEWLINES); | |
| 1996 | -$td->runtest("tokenize content streams", | |
| 1997 | - {$td->COMMAND => "test_driver 37 tokenize-content-streams.pdf"}, | |
| 1998 | - {$td->FILE => "tokenize-content-streams.out", | |
| 1999 | - $td->EXIT_STATUS => 0}, | |
| 2000 | - $td->NORMALIZE_NEWLINES); | |
| 2001 | -$td->runtest("terminate parsing", | |
| 2002 | - {$td->COMMAND => "test_driver 37 terminate-parsing.pdf"}, | |
| 2003 | - {$td->FILE => "terminate-parsing.out", | |
| 2004 | - $td->EXIT_STATUS => 0}, | |
| 2005 | - $td->NORMALIZE_NEWLINES); | |
| 2006 | -$td->runtest("content stream errors", | |
| 2007 | - {$td->COMMAND => "qpdf --check content-stream-errors.pdf"}, | |
| 2008 | - {$td->FILE => "content-stream-errors.out", | |
| 2009 | - $td->EXIT_STATUS => 3}, | |
| 2010 | - $td->NORMALIZE_NEWLINES); | |
| 2011 | - | |
| 2012 | -$td->runtest("ensure arguments to R are direct", | |
| 2013 | - {$td->COMMAND => "qpdf --check indirect-r-arg.pdf"}, | |
| 2014 | - {$td->FILE => "indirect-r-arg.out", $td->EXIT_STATUS => 3}, | |
| 2015 | - $td->NORMALIZE_NEWLINES); | |
| 2016 | -$td->runtest("no trailing space in xref table", | |
| 2017 | - {$td->COMMAND => "qpdf --check no-space-in-xref.pdf"}, | |
| 2018 | - {$td->FILE => "no-space-in-xref.out", $td->EXIT_STATUS => 0}, | |
| 2019 | - $td->NORMALIZE_NEWLINES); | |
| 2020 | - | |
| 2021 | -# An array is split across multiple content streams starting object | |
| 2022 | -# 42. This was reported in github issue 73. The file is modified from | |
| 2023 | -# that example. | |
| 2024 | -$td->runtest("parse split content stream", | |
| 2025 | - {$td->COMMAND => "qpdf --check split-content-stream.pdf"}, | |
| 2026 | - {$td->FILE => "split-content-stream.out", $td->EXIT_STATUS => 0}, | |
| 2027 | - $td->NORMALIZE_NEWLINES); | |
| 2028 | -$td->runtest("split content stream errors", | |
| 2029 | - {$td->COMMAND => "qpdf --check split-content-stream-errors.pdf"}, | |
| 2030 | - {$td->FILE => "split-content-stream-errors.out", | |
| 2031 | - $td->EXIT_STATUS => 2}, | |
| 2032 | - $td->NORMALIZE_NEWLINES); | |
| 2033 | - | |
| 2034 | -show_ntests(); | |
| 2035 | -# ---------- | |
| 2036 | -$td->notify("--- Custom Pipeline ---"); | |
| 2037 | -$n_tests += 2; | |
| 2038 | - | |
| 2039 | -$td->runtest("output to custom pipeline", | |
| 2040 | - {$td->COMMAND => "test_driver 33 minimal.pdf"}, | |
| 2041 | - {$td->STRING => "test 33 done\n", $td->EXIT_STATUS => 0}, | |
| 2042 | - $td->NORMALIZE_NEWLINES); | |
| 2043 | -$td->runtest("check output", | |
| 2044 | - {$td->FILE => "a.pdf"}, | |
| 2045 | - {$td->FILE => "custom-pipeline.pdf"}); | |
| 2046 | - | |
| 2047 | -show_ntests(); | |
| 2048 | -# ---------- | |
| 2049 | -$td->notify("--- Object stream cases ---"); | |
| 2050 | -$n_tests += 3; | |
| 2051 | - | |
| 2052 | -# The file override-compressed-object.pdf contains an object stream | |
| 2053 | -# with four strings in it. The file is then appended. The appended | |
| 2054 | -# section overrides one of the four strings with a string in another | |
| 2055 | -# object stream and another one in an uncompressed object. The other | |
| 2056 | -# two strings are left alone. The test case exercises that all four | |
| 2057 | -# objects have the correct value. | |
| 2058 | -$td->runtest("overridden compressed objects", | |
| 2059 | - {$td->COMMAND => "test_driver 38 override-compressed-object.pdf"}, | |
| 2060 | - {$td->FILE => "override-compressed-object.out", | |
| 2061 | - $td->EXIT_STATUS => 0}, | |
| 2062 | - $td->NORMALIZE_NEWLINES); | |
| 2063 | - | |
| 2064 | -$td->runtest("generate object streams for gen > 0", | |
| 2065 | - {$td->COMMAND => "qpdf --qdf --static-id" . | |
| 2066 | - " --object-streams=generate gen1.pdf a.pdf"}, | |
| 2067 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2068 | -$td->runtest("check file", | |
| 2069 | - {$td->FILE => "a.pdf"}, | |
| 2070 | - {$td->FILE => "gen1.qdf"}); | |
| 2071 | - | |
| 2072 | -show_ntests(); | |
| 2073 | -# ---------- | |
| 2074 | -$td->notify("--- Bound checks ---"); | |
| 2075 | -$n_tests += 3; | |
| 2076 | - | |
| 2077 | -$td->runtest("bounds check linearization data 1", | |
| 2078 | - {$td->COMMAND => "qpdf --check linearization-bounds-1.pdf"}, | |
| 2079 | - {$td->FILE => "linearization-bounds-1.out", | |
| 2080 | - $td->EXIT_STATUS => 3}, | |
| 2081 | - $td->NORMALIZE_NEWLINES); | |
| 2082 | -$td->runtest("bounds check linearization data 2", | |
| 2083 | - {$td->COMMAND => "qpdf --check linearization-bounds-2.pdf"}, | |
| 2084 | - {$td->FILE => "linearization-bounds-2.out", | |
| 2085 | - $td->EXIT_STATUS => 3}, | |
| 2086 | - $td->NORMALIZE_NEWLINES); | |
| 2087 | -# Throws runtime error, not bad_alloc | |
| 2088 | -$td->runtest("sanity check array size", | |
| 2089 | - {$td->COMMAND => | |
| 2090 | - "qpdf --check linearization-large-vector-alloc.pdf"}, | |
| 2091 | - {$td->FILE => "linearization-large-vector-alloc.out", | |
| 2092 | - $td->EXIT_STATUS => 3}, | |
| 2093 | - $td->NORMALIZE_NEWLINES); | |
| 2094 | - | |
| 2095 | -show_ntests(); | |
| 2096 | -# ---------- | |
| 2097 | -$td->notify("--- Page errors ---"); | |
| 2098 | -$n_tests += 5; | |
| 2099 | - | |
| 2100 | -$td->runtest("handle page no with contents", | |
| 2101 | - {$td->COMMAND => "qpdf --show-pages page-no-content.pdf"}, | |
| 2102 | - {$td->FILE => "page-no-content.out", $td->EXIT_STATUS => 0}, | |
| 2103 | - $td->NORMALIZE_NEWLINES); | |
| 2104 | -$td->runtest("check no type key for page nodes", | |
| 2105 | - {$td->COMMAND => "qpdf --check no-pages-types.pdf"}, | |
| 2106 | - {$td->FILE => "no-pages-types.out", $td->EXIT_STATUS => 3}, | |
| 2107 | - $td->NORMALIZE_NEWLINES); | |
| 2108 | -$td->runtest("no type key for page nodes", | |
| 2109 | - {$td->COMMAND => "qpdf --static-id --split-pages no-pages-types.pdf a-split-out.pdf"}, | |
| 2110 | - {$td->FILE => "no-pages-types-fix.out", $td->EXIT_STATUS => 3}, | |
| 2111 | - $td->NORMALIZE_NEWLINES); | |
| 2112 | -$td->runtest("check output", | |
| 2113 | - {$td->FILE => "a-split-out-1.pdf"}, | |
| 2114 | - {$td->FILE => "no-pages-types-fixed.pdf"}); | |
| 2115 | -$td->runtest("detect loops in pages structure", | |
| 2116 | - {$td->COMMAND => "qpdf --check pages-loop.pdf"}, | |
| 2117 | - {$td->FILE => "pages-loop.out", $td->EXIT_STATUS => 2}, | |
| 2118 | - $td->NORMALIZE_NEWLINES); | |
| 2119 | - | |
| 2120 | -show_ntests(); | |
| 2121 | -# ---------- | |
| 2122 | -$td->notify("--- Xref ---"); | |
| 2123 | -$n_tests += 6; | |
| 2124 | - | |
| 2125 | -# Handle file with invalid xref table and object 0 as a regular object | |
| 2126 | -# (bug 3159950). | |
| 2127 | -$td->runtest("check obj0.pdf", | |
| 2128 | - {$td->COMMAND => "qpdf --check obj0.pdf"}, | |
| 2129 | - {$td->FILE => "obj0-check.out", | |
| 2130 | - $td->EXIT_STATUS => 3}, | |
| 2131 | - $td->NORMALIZE_NEWLINES); | |
| 2132 | - | |
| 2133 | -# Demonstrate show-xref after check and not after check to illustrate | |
| 2134 | -# that it can dump the real xref or the recovered xref. | |
| 2135 | -$td->runtest("dump bad xref", | |
| 2136 | - {$td->COMMAND => "qpdf --show-xref bad-xref-entry.pdf"}, | |
| 2137 | - {$td->FILE => "bad-xref-entry.out", | |
| 2138 | - $td->EXIT_STATUS => 0}, | |
| 2139 | - $td->NORMALIZE_NEWLINES); | |
| 2140 | -# Test @file here too. | |
| 2141 | -open(F, ">args") or die; | |
| 2142 | -print F "--check\n"; | |
| 2143 | -print F "--show-xref\n"; | |
| 2144 | -close(F); | |
| 2145 | -$td->runtest("dump corrected bad xref", | |
| 2146 | - {$td->COMMAND => "qpdf \@args bad-xref-entry.pdf"}, | |
| 2147 | - {$td->FILE => "bad-xref-entry-corrected.out", | |
| 2148 | - $td->EXIT_STATUS => 3}, | |
| 2149 | - $td->NORMALIZE_NEWLINES); | |
| 2150 | -unlink "args"; | |
| 2151 | - | |
| 2152 | -$td->runtest("combine show and --pages", | |
| 2153 | - {$td->COMMAND => | |
| 2154 | - "qpdf --empty --pages minimal.pdf -- --show-pages"}, | |
| 2155 | - {$td->FILE => "show-pages-pages.out", | |
| 2156 | - $td->EXIT_STATUS => 0}, | |
| 2157 | - $td->NORMALIZE_NEWLINES); | |
| 2158 | - | |
| 2159 | -$td->runtest("show number of pages", | |
| 2160 | - {$td->COMMAND => | |
| 2161 | - "qpdf --show-npages 20-pages.pdf --password=user"}, | |
| 2162 | - {$td->STRING => "20\n", $td->EXIT_STATUS => 0}, | |
| 2163 | - $td->NORMALIZE_NEWLINES); | |
| 2164 | - | |
| 2165 | -# Issue 482 -- don't range check fields[2] for xref entry type 0. | |
| 2166 | -$td->runtest("out of range in deleted object", | |
| 2167 | - {$td->COMMAND => "qpdf --check xref-range.pdf"}, | |
| 2168 | - {$td->FILE => "xref-range.out", $td->EXIT_STATUS => 0}, | |
| 2169 | - $td->NORMALIZE_NEWLINES); | |
| 2170 | - | |
| 2171 | -show_ntests(); | |
| 2172 | -# ---------- | |
| 2173 | -$td->notify("--- Overwrite self ---"); | |
| 2174 | -$n_tests += 3; | |
| 2175 | - | |
| 2176 | -copy("minimal.pdf", "a.pdf"); | |
| 2177 | -copy("minimal.pdf", "split-out.pdf"); | |
| 2178 | -# Also tests @- for reading args from stdin | |
| 2179 | -$td->runtest("don't overwrite self", | |
| 2180 | - {$td->COMMAND => "(echo a.pdf; echo a.pdf) | qpdf \@-"}, | |
| 2181 | - {$td->REGEXP => "input file and output file are the same.*", | |
| 2182 | - $td->EXIT_STATUS => 2}); | |
| 2183 | -$td->runtest("output is not really output for split", | |
| 2184 | - {$td->COMMAND => "qpdf --split-pages split-out.pdf split-out.pdf"}, | |
| 2185 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2186 | -$td->runtest("don't overwrite self (split)", | |
| 2187 | - {$td->COMMAND => | |
| 2188 | - "qpdf --split-pages split-out-1.pdf split-out.pdf"}, | |
| 2189 | - {$td->REGEXP => | |
| 2190 | - ".*split pages would overwrite.* split-out-1.pdf", | |
| 2191 | - $td->EXIT_STATUS => 2}); | |
| 2192 | - | |
| 2193 | -show_ntests(); | |
| 2194 | -# ---------- | |
| 2195 | -$td->notify("--- Progress reporting ---"); | |
| 2196 | -$n_tests += 1; | |
| 2197 | - | |
| 2198 | -$td->runtest("progress report on small file", | |
| 2199 | - {$td->COMMAND => "qpdf --progress minimal.pdf a.pdf", | |
| 2200 | - $td->FILTER => "perl filter-progress.pl"}, | |
| 2201 | - {$td->FILE => "small-progress.out", $td->EXIT_STATUS => 0}, | |
| 2202 | - $td->NORMALIZE_NEWLINES); | |
| 2203 | - | |
| 2204 | -show_ntests(); | |
| 2205 | -# ---------- | |
| 2206 | -$td->notify("--- Type checks ---"); | |
| 2207 | -$n_tests += 5; | |
| 2208 | -# Whenever object-types.pdf is edited, object-types-os.pdf should be | |
| 2209 | -# regenerated. | |
| 2210 | -$td->runtest("ensure object-types-os is up-to-date", | |
| 2211 | - {$td->COMMAND => | |
| 2212 | - "qpdf" . | |
| 2213 | - " --object-streams=generate" . | |
| 2214 | - " --deterministic-id" . | |
| 2215 | - " --stream-data=uncompress" . | |
| 2216 | - " object-types.pdf a.pdf"}, | |
| 2217 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2218 | -$td->runtest("check file", | |
| 2219 | - {$td->FILE => "a.pdf"}, | |
| 2220 | - {$td->FILE => "object-types-os.pdf"}); | |
| 2221 | -$td->runtest("type checks", | |
| 2222 | - {$td->COMMAND => "test_driver 42 object-types.pdf"}, | |
| 2223 | - {$td->FILE => "object-types.out", | |
| 2224 | - $td->EXIT_STATUS => 0}, | |
| 2225 | - $td->NORMALIZE_NEWLINES); | |
| 2226 | -$td->runtest("type checks with object streams", | |
| 2227 | - {$td->COMMAND => "test_driver 42 object-types-os.pdf"}, | |
| 2228 | - {$td->FILE => "object-types-os.out", | |
| 2229 | - $td->EXIT_STATUS => 0}, | |
| 2230 | - $td->NORMALIZE_NEWLINES); | |
| 2231 | -$td->runtest("compound type checks", | |
| 2232 | - {$td->COMMAND => "test_driver 82 object-types-os.pdf"}, | |
| 2233 | - {$td->STRING => "test 82 done\n", $td->EXIT_STATUS => 0}, | |
| 2234 | - $td->NORMALIZE_NEWLINES); | |
| 2235 | - | |
| 2236 | -# ---------- | |
| 2237 | -$td->notify("--- Coalesce contents ---"); | |
| 2238 | -$n_tests += 8; | |
| 2239 | - | |
| 2240 | -$td->runtest("qdf with normalize warnings", | |
| 2241 | - {$td->COMMAND => | |
| 2242 | - "qpdf --qdf --static-id split-tokens.pdf a.pdf"}, | |
| 2243 | - {$td->FILE => "normalize-warnings.out", $td->EXIT_STATUS => 3}, | |
| 2244 | - $td->NORMALIZE_NEWLINES); | |
| 2245 | -$td->runtest("check output", | |
| 2246 | - {$td->FILE => "a.pdf"}, | |
| 2247 | - {$td->FILE => "split-tokens.qdf"}); | |
| 2248 | -$td->runtest("coalesce to qdf", | |
| 2249 | - {$td->COMMAND => | |
| 2250 | - "qpdf --qdf --static-id coalesce.pdf a.pdf"}, | |
| 2251 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2252 | - $td->NORMALIZE_NEWLINES); | |
| 2253 | -$td->runtest("check output", | |
| 2254 | - {$td->FILE => "a.pdf"}, | |
| 2255 | - {$td->FILE => "coalesce.qdf"}); | |
| 2256 | -$td->runtest("coalesce contents with qdf", | |
| 2257 | - {$td->COMMAND => | |
| 2258 | - "qpdf --qdf --static-id" . | |
| 2259 | - " --coalesce-contents coalesce.pdf a.pdf"}, | |
| 2260 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2261 | -$td->runtest("check output", | |
| 2262 | - {$td->FILE => "a.pdf"}, | |
| 2263 | - {$td->FILE => "coalesce-out.qdf"}); | |
| 2264 | -$td->runtest("coalesce contents without qdf", | |
| 2265 | - {$td->COMMAND => | |
| 2266 | - "qpdf --static-id" . | |
| 2267 | - " --coalesce-contents coalesce.pdf a.pdf"}, | |
| 2268 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2269 | -$td->runtest("check output", | |
| 2270 | - {$td->FILE => "a.pdf"}, | |
| 2271 | - {$td->FILE => "coalesce-out.pdf"}); | |
| 2272 | - | |
| 2273 | -show_ntests(); | |
| 2274 | -# ---------- | |
| 2275 | -$td->notify("--- Page with no contents ---"); | |
| 2276 | -$n_tests += 7; | |
| 2277 | - | |
| 2278 | -$td->runtest("check no contents", | |
| 2279 | - {$td->COMMAND => "qpdf --check no-contents.pdf"}, | |
| 2280 | - {$td->FILE => "no-contents-check.out", $td->EXIT_STATUS => 0}, | |
| 2281 | - $td->NORMALIZE_NEWLINES); | |
| 2282 | - | |
| 2283 | -foreach my $arg ('--qdf', '--coalesce-contents', '') | |
| 2284 | -{ | |
| 2285 | - $td->runtest("convert no contents ($arg)", | |
| 2286 | - {$td->COMMAND => | |
| 2287 | - "qpdf $arg --static-id no-contents.pdf a.pdf"}, | |
| 2288 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2289 | - | |
| 2290 | - my $suf = $arg; | |
| 2291 | - $suf =~ s/--//; | |
| 2292 | - if ($suf eq '') | |
| 2293 | - { | |
| 2294 | - $suf = "none"; | |
| 2295 | - } | |
| 2296 | - $td->runtest("check output", | |
| 2297 | - {$td->FILE => "a.pdf"}, | |
| 2298 | - {$td->FILE => "no-contents-$suf.pdf"}); | |
| 2299 | -} | |
| 2300 | - | |
| 2301 | -show_ntests(); | |
| 2302 | -# ---------- | |
| 2303 | -$td->notify("--- Token filters ---"); | |
| 2304 | -$n_tests += 2; | |
| 2305 | - | |
| 2306 | -$td->runtest("token filter", | |
| 2307 | - {$td->COMMAND => "test_driver 41 coalesce.pdf"}, | |
| 2308 | - {$td->STRING => "test 41 done\n", $td->EXIT_STATUS => 0}, | |
| 2309 | - $td->NORMALIZE_NEWLINES); | |
| 2310 | -$td->runtest("check output", | |
| 2311 | - {$td->FILE => "a.pdf"}, | |
| 2312 | - {$td->FILE => "token-filters-out.pdf"}); | |
| 2313 | - | |
| 2314 | -show_ntests(); | |
| 2315 | -# ---------- | |
| 2316 | -$td->notify("--- Newline before endstream ---"); | |
| 2317 | -$n_tests += 12; | |
| 2318 | - | |
| 2319 | -# From issue 133, http://verapdf.org/software/ is an open source | |
| 2320 | -# package that can verify PDF/A compliance. This could potentially be | |
| 2321 | -# useful for manual or automated verification that qpdf doesn't break | |
| 2322 | -# PDF/A compliance should that ever be desired. | |
| 2323 | - | |
| 2324 | -foreach my $d ( | |
| 2325 | - ['--qdf', 'qdf', 'qdf'], | |
| 2326 | - ['--newline-before-endstream', 'newline', 'nl'], | |
| 2327 | - ['--qdf --newline-before-endstream', 'newline and qdf', 'nl-qdf'], | |
| 2328 | - ['--object-streams=generate --newline-before-endstream', | |
| 2329 | - 'newline and object streams', 'nl-objstm'], | |
| 2330 | - ) | |
| 2331 | -{ | |
| 2332 | - my ($flags, $description, $suffix) = @$d; | |
| 2333 | - $td->runtest("newline before endstream: $description", | |
| 2334 | - {$td->COMMAND => "qpdf --static-id --stream-data=preserve" . | |
| 2335 | - " $flags streams-with-newlines.pdf a.pdf"}, | |
| 2336 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2337 | - $td->NORMALIZE_NEWLINES); | |
| 2338 | - $td->runtest("check output ($description)", | |
| 2339 | - {$td->FILE => "a.pdf"}, | |
| 2340 | - {$td->FILE => "newline-before-endstream-$suffix.pdf"}); | |
| 2341 | - if ($flags =~ /qdf/) | |
| 2342 | - { | |
| 2343 | - $td->runtest("fix-qdf", | |
| 2344 | - {$td->COMMAND => "fix-qdf a.pdf"}, | |
| 2345 | - {$td->FILE => "a.pdf", $td->EXIT_STATUS => 0}); | |
| 2346 | - } | |
| 2347 | -} | |
| 2348 | - | |
| 2349 | -$td->runtest("newline before endstream (C)", | |
| 2350 | - {$td->COMMAND => | |
| 2351 | - "qpdf-ctest 22 streams-with-newlines.pdf '' a.pdf"}, | |
| 2352 | - {$td->STRING => "C test 22 done\n", $td->EXIT_STATUS => 0}, | |
| 2353 | - $td->NORMALIZE_NEWLINES); | |
| 2354 | -$td->runtest("check output", | |
| 2355 | - {$td->FILE => "a.pdf"}, | |
| 2356 | - {$td->FILE => "newline-before-endstream-nl.pdf"}); | |
| 2357 | - | |
| 2358 | -show_ntests(); | |
| 2359 | -# ---------- | |
| 2360 | -$td->notify("--- Split Pages ---"); | |
| 2361 | -# sp = split-pages | |
| 2362 | -my @sp_cases = ( | |
| 2363 | - [11, '%d at beginning', '', '%d_split-out.zdf'], | |
| 2364 | - [11, '%d at end', '--qdf', 'split-out.zdf_%d'], | |
| 2365 | - [11, '%d in middle', '--allow-weak-crypto --encrypt u o 128 --', | |
| 2366 | - 'a-%d-split-out.zdf'], | |
| 2367 | - [11, 'pdf extension', '', 'split-out.Pdf'], | |
| 2368 | - [4, 'fallback', '--pages 11-pages.pdf 1-3 minimal.pdf --', 'split-out'], | |
| 2369 | - [1, 'broken data', '--pages broken-lzw.pdf --', 'split-out.pdf', | |
| 2370 | - {$td->FILE => "broken-lzw.out", $td->EXIT_STATUS => 3}], | |
| 2371 | - ); | |
| 2372 | -$n_tests += 42; | |
| 2373 | -$n_compare_pdfs += 2; | |
| 2374 | -for (@sp_cases) | |
| 2375 | -{ | |
| 2376 | - $n_tests += 1 + $_->[0]; | |
| 2377 | -} | |
| 2378 | - | |
| 2379 | -$td->runtest("split page group > 1", | |
| 2380 | - {$td->COMMAND => "qpdf --static-id --split-pages=5 11-pages.pdf" . | |
| 2381 | - " --verbose split-out-group.pdf"}, | |
| 2382 | - {$td->FILE => "split-pages-group.out", $td->EXIT_STATUS => 0}, | |
| 2383 | - $td->NORMALIZE_NEWLINES); | |
| 2384 | -foreach my $f ('01-05', '06-10', '11-11') | |
| 2385 | -{ | |
| 2386 | - $td->runtest("check out group $f", | |
| 2387 | - {$td->FILE => "split-out-group-$f.pdf"}, | |
| 2388 | - {$td->FILE => "split-exp-group-$f.pdf"}); | |
| 2389 | -} | |
| 2390 | - | |
| 2391 | -$td->runtest("no split-pages to stdout", | |
| 2392 | - {$td->COMMAND => "qpdf --split-pages 11-pages.pdf -"}, | |
| 2393 | - {$td->FILE => "split-pages-stdout.out", $td->EXIT_STATUS => 2}, | |
| 2394 | - $td->NORMALIZE_NEWLINES); | |
| 2395 | - | |
| 2396 | -$td->runtest("split page with shared resources", | |
| 2397 | - {$td->COMMAND => "qpdf --qdf --static-id --split-pages=4". | |
| 2398 | - " shared-images.pdf split-out-shared.pdf"}, | |
| 2399 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2400 | -foreach my $i (qw(01-04 05-08 09-10)) | |
| 2401 | -{ | |
| 2402 | - $td->runtest("check output ($i)", | |
| 2403 | - {$td->FILE => "split-out-shared-$i.pdf"}, | |
| 2404 | - {$td->FILE => "shared-split-$i.pdf"}); | |
| 2405 | -} | |
| 2406 | - | |
| 2407 | -$td->runtest("split page with labels", | |
| 2408 | - {$td->COMMAND => "qpdf --qdf --static-id --split-pages=6". | |
| 2409 | - " 11-pages-with-labels.pdf split-out-labels.pdf"}, | |
| 2410 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2411 | -foreach my $i (qw(01-06 07-11)) | |
| 2412 | -{ | |
| 2413 | - $td->runtest("check output ($i)", | |
| 2414 | - {$td->FILE => "split-out-labels-$i.pdf"}, | |
| 2415 | - {$td->FILE => "labels-split-$i.pdf"}); | |
| 2416 | -} | |
| 2417 | - | |
| 2418 | -# See comments in TODO about these expected failures. Search for | |
| 2419 | -# "split page with outlines". | |
| 2420 | -$td->runtest("split page with outlines", | |
| 2421 | - {$td->COMMAND => "qpdf --qdf --static-id --split-pages=10". | |
| 2422 | - " outlines-with-actions.pdf split-out-outlines.pdf"}, | |
| 2423 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2424 | -foreach my $i (qw(01-10 11-20 21-30)) | |
| 2425 | -{ | |
| 2426 | - $td->runtest("check output ($i)", | |
| 2427 | - {$td->FILE => "split-out-outlines-$i.pdf"}, | |
| 2428 | - {$td->FILE => "outlines-split-$i.pdf"}, | |
| 2429 | - $td->EXPECT_FAILURE) | |
| 2430 | -} | |
| 2431 | - | |
| 2432 | -foreach my $d (@sp_cases) | |
| 2433 | -{ | |
| 2434 | - my ($n, $description, $xargs, $out, $exp) = @$d; | |
| 2435 | - if (! defined $exp) | |
| 2436 | - { | |
| 2437 | - $exp = {$td->STRING => "", $td->EXIT_STATUS => 0}; | |
| 2438 | - } | |
| 2439 | - $td->runtest("split pages " . $description, | |
| 2440 | - {$td->COMMAND => | |
| 2441 | - "qpdf --static-id --split-pages 11-pages.pdf" . | |
| 2442 | - " $xargs $out"}, | |
| 2443 | - $exp, | |
| 2444 | - $td->NORMALIZE_NEWLINES); | |
| 2445 | - my $pattern = $out; | |
| 2446 | - my $nlen = length($n); | |
| 2447 | - if ($pattern =~ m/\%d/) | |
| 2448 | - { | |
| 2449 | - $pattern =~ s/\%d/\%0${nlen}d/; | |
| 2450 | - } | |
| 2451 | - elsif ($pattern =~ m/\.pdf$/i) | |
| 2452 | - { | |
| 2453 | - $pattern =~ s/(\.pdf$)/-%0${nlen}d$1/i; | |
| 2454 | - } | |
| 2455 | - else | |
| 2456 | - { | |
| 2457 | - $pattern .= "-%0${nlen}d"; | |
| 2458 | - } | |
| 2459 | - for (my $i = 1; $i <= $n; ++$i) | |
| 2460 | - { | |
| 2461 | - my $actual = sprintf($pattern, $i); | |
| 2462 | - my $expected = $actual; | |
| 2463 | - $expected =~ s/split-out/split-exp/; | |
| 2464 | - $td->runtest("check output page $i ($description)", | |
| 2465 | - {$td->FILE => $actual}, | |
| 2466 | - {$td->FILE => $expected}); | |
| 2467 | - } | |
| 2468 | -} | |
| 2469 | - | |
| 2470 | -$td->runtest("split shared font, xobject", | |
| 2471 | - {$td->COMMAND => | |
| 2472 | - "qpdf --static-id --qdf --no-original-object-ids" . | |
| 2473 | - " --split-pages shared-font-xobject.pdf" . | |
| 2474 | - " split-out-shared-font-xobject.pdf"}, | |
| 2475 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2476 | -foreach my $i (qw(1 2 3 4)) | |
| 2477 | -{ | |
| 2478 | - $td->runtest("check output ($i)", | |
| 2479 | - {$td->FILE => "split-out-shared-font-xobject-$i.pdf"}, | |
| 2480 | - {$td->FILE => "shared-font-xobject-split-$i.pdf"}); | |
| 2481 | -} | |
| 2482 | - | |
| 2483 | -$td->runtest("unreferenced resources with bad token", | |
| 2484 | - {$td->COMMAND => | |
| 2485 | - "qpdf --qdf --static-id --split-pages=2" . | |
| 2486 | - " --remove-unreferenced-resources=yes" . | |
| 2487 | - " split-tokens.pdf split-out-bad-token.pdf"}, | |
| 2488 | - {$td->FILE => "split-tokens-split.out", $td->EXIT_STATUS => 3}, | |
| 2489 | - $td->NORMALIZE_NEWLINES); | |
| 2490 | -$td->runtest("check output", | |
| 2491 | - {$td->FILE => "split-out-bad-token-1-2.pdf"}, | |
| 2492 | - {$td->FILE => "split-tokens-split-1-2.pdf"}); | |
| 2493 | -$td->runtest("--no-warn with proxied warnings during split", | |
| 2494 | - {$td->COMMAND => | |
| 2495 | - "qpdf --qdf --static-id --split-pages=2" . | |
| 2496 | - " --no-warn --remove-unreferenced-resources=yes" . | |
| 2497 | - " split-tokens.pdf split-out-bad-token.pdf"}, | |
| 2498 | - {$td->STRING => "", $td->EXIT_STATUS => 3}, | |
| 2499 | - $td->NORMALIZE_NEWLINES); | |
| 2500 | - | |
| 2501 | -$td->runtest("shared images in form xobject", | |
| 2502 | - {$td->COMMAND => "qpdf --qdf --static-id --split-pages". | |
| 2503 | - " shared-form-images.pdf split-out-shared-form.pdf"}, | |
| 2504 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2505 | -foreach my $i (qw(1 2 3 4 5 6)) | |
| 2506 | -{ | |
| 2507 | - $td->runtest("check output ($i)", | |
| 2508 | - {$td->FILE => "split-out-shared-form-$i.pdf"}, | |
| 2509 | - {$td->FILE => "shared-form-split-$i.pdf"}); | |
| 2510 | -} | |
| 2511 | -$td->runtest("merge for compare", | |
| 2512 | - {$td->COMMAND => "qpdf --static-id --empty --pages" . | |
| 2513 | - " split-out-shared-form*.pdf -- a.pdf"}, | |
| 2514 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2515 | -$td->runtest("check output", | |
| 2516 | - {$td->FILE => "a.pdf"}, | |
| 2517 | - {$td->FILE => "shared-form-images-merged.pdf"}); | |
| 2518 | -compare_pdfs("shared-form-images.pdf", "a.pdf"); | |
| 2519 | - | |
| 2520 | -$td->runtest("shared form xobject subkey", | |
| 2521 | - {$td->COMMAND => "qpdf --qdf --static-id --split-pages". | |
| 2522 | - " shared-form-images-xobject.pdf" . | |
| 2523 | - " split-out-shared-form-xobject.pdf"}, | |
| 2524 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2525 | -foreach my $i (qw(1 2)) | |
| 2526 | -{ | |
| 2527 | - $td->runtest("check output ($i)", | |
| 2528 | - {$td->FILE => "split-out-shared-form-xobject-$i.pdf"}, | |
| 2529 | - {$td->FILE => "shared-form-xobject-split-$i.pdf"}); | |
| 2530 | -} | |
| 2531 | - | |
| 2532 | -my @fo_resources = (['form-xobjects-no-resources', 1], | |
| 2533 | - ['form-xobjects-some-resources1', 0], | |
| 2534 | - ['form-xobjects-some-resources2', 0]); | |
| 2535 | -foreach my $d (@fo_resources) | |
| 2536 | -{ | |
| 2537 | - my ($f, $compare) = @$d; | |
| 2538 | - $td->runtest("split $f", | |
| 2539 | - {$td->COMMAND => | |
| 2540 | - "qpdf --empty --static-id --pages $f.pdf 1 --" . | |
| 2541 | - " --remove-unreferenced-resources=yes a.pdf"}, | |
| 2542 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2543 | - $td->NORMALIZE_NEWLINES); | |
| 2544 | - $td->runtest("check output ($f)", | |
| 2545 | - {$td->FILE => "a.pdf"}, | |
| 2546 | - {$td->FILE => "$f-out.pdf"}); | |
| 2547 | - if ($compare) | |
| 2548 | - { | |
| 2549 | - compare_pdfs("$f.pdf", "a.pdf"); | |
| 2550 | - } | |
| 2551 | -} | |
| 2552 | - | |
| 2553 | -show_ntests(); | |
| 2554 | -# ---------- | |
| 2555 | -$td->notify("--- Keep Files Open ---"); | |
| 2556 | -$n_tests += 4; | |
| 2557 | - | |
| 2558 | -{ # local scope | |
| 2559 | - open(F, "<minimal.pdf") or die; | |
| 2560 | - local $/ = undef; | |
| 2561 | - binmode F; | |
| 2562 | - my $content = <F>; | |
| 2563 | - close(F); | |
| 2564 | - for (my $i = 1; $i <= 51; ++$i) | |
| 2565 | - { | |
| 2566 | - open(F, sprintf(">%03d-kfo.pdf", $i)) or die; | |
| 2567 | - binmode F; | |
| 2568 | - print F $content; | |
| 2569 | - close(F); | |
| 2570 | - } | |
| 2571 | -} | |
| 2572 | -$td->runtest("automatic disable keep files open", | |
| 2573 | - {$td->COMMAND => | |
| 2574 | - "qpdf --verbose --static-id --empty" . | |
| 2575 | - " --keep-files-open-threshold=50" . | |
| 2576 | - " --pages *kfo.pdf -- a.pdf"}, | |
| 2577 | - {$td->FILE => "disable-kfo.out", $td->EXIT_STATUS => 0}, | |
| 2578 | - $td->NORMALIZE_NEWLINES); | |
| 2579 | -$td->runtest("don't disable keep files open", | |
| 2580 | - {$td->COMMAND => | |
| 2581 | - "qpdf --verbose --static-id --empty" . | |
| 2582 | - " --pages 01*kfo.pdf -- a.pdf"}, | |
| 2583 | - {$td->FILE => "enable-kfo.out", $td->EXIT_STATUS => 0}, | |
| 2584 | - $td->NORMALIZE_NEWLINES); | |
| 2585 | -$td->runtest("explict keep files open", | |
| 2586 | - {$td->COMMAND => | |
| 2587 | - "qpdf --verbose --static-id --keep-files-open=y --empty" . | |
| 2588 | - " --pages 00?-kfo.pdf -- a.pdf"}, | |
| 2589 | - {$td->FILE => "kfo-y.out", $td->EXIT_STATUS => 0}, | |
| 2590 | - $td->NORMALIZE_NEWLINES); | |
| 2591 | -$td->runtest("explicit keep files open = n", | |
| 2592 | - {$td->COMMAND => | |
| 2593 | - "qpdf --verbose --static-id --keep-files-open=n --empty" . | |
| 2594 | - " --pages 00?-kfo.pdf -- a.pdf"}, | |
| 2595 | - {$td->FILE => "kfo-n.out", $td->EXIT_STATUS => 0}, | |
| 2596 | - $td->NORMALIZE_NEWLINES); | |
| 2597 | - | |
| 2598 | -show_ntests(); | |
| 2599 | -# ---------- | |
| 2600 | -$td->notify("--- Rotate Pages ---"); | |
| 2601 | -$n_tests += 18; | |
| 2602 | -# Do absolute, positive, and negative on ranges that include | |
| 2603 | -# inherited and non-inherited. | |
| 2604 | -# Pages 11-15 inherit /Rotate 90 | |
| 2605 | -# Pages 1 and 2 have explicit /Rotate 270 | |
| 2606 | -# Pages 16 and 17 have explicit /Rotate 180 | |
| 2607 | - | |
| 2608 | -$td->runtest("page rotation", | |
| 2609 | - {$td->COMMAND => "qpdf --static-id to-rotate.pdf a.pdf" . | |
| 2610 | - " --rotate=+90:1,4,11,16" . | |
| 2611 | - " --rotate=180:2,5,12-13" . | |
| 2612 | - " --rotate=-90:3,15,17,18"}, | |
| 2613 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2614 | -$td->runtest("check output", | |
| 2615 | - {$td->FILE => "a.pdf"}, | |
| 2616 | - {$td->FILE => "rotated.pdf"}); | |
| 2617 | - | |
| 2618 | -$td->runtest("remove rotation", | |
| 2619 | - {$td->COMMAND => "qpdf --static-id rotated.pdf a.pdf" . | |
| 2620 | - " --qdf --no-original-object-ids --rotate=0"}, | |
| 2621 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2622 | -$td->runtest("check output", | |
| 2623 | - {$td->FILE => "a.pdf"}, | |
| 2624 | - {$td->FILE => "unrotated.pdf"}); | |
| 2625 | - | |
| 2626 | -$td->runtest("rotate all pages", | |
| 2627 | - {$td->COMMAND => | |
| 2628 | - "qpdf --static-id --rotate=180 minimal.pdf a.pdf"}, | |
| 2629 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2630 | -$td->runtest("check output", | |
| 2631 | - {$td->FILE => "a.pdf"}, | |
| 2632 | - {$td->FILE => "minimal-rotated.pdf"}); | |
| 2633 | - | |
| 2634 | -$td->runtest("flatten with inherited rotate", | |
| 2635 | - {$td->COMMAND => | |
| 2636 | - "qpdf --static-id --flatten-rotation" . | |
| 2637 | - " inherited-rotate.pdf a.pdf"}, | |
| 2638 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2639 | -$td->runtest("check output", | |
| 2640 | - {$td->FILE => "a.pdf"}, | |
| 2641 | - {$td->FILE => "inherited-flattened.pdf"}); | |
| 2642 | - | |
| 2643 | -foreach my $angle (qw(90 180 270)) | |
| 2644 | -{ | |
| 2645 | - $td->runtest("rotate annotations", | |
| 2646 | - {$td->COMMAND => | |
| 2647 | - "qpdf --static-id --qdf --rotate=$angle" . | |
| 2648 | - " --flatten-rotation --no-original-object-ids" . | |
| 2649 | - " form-fields-and-annotations.pdf a.pdf"}, | |
| 2650 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 2651 | - $td->runtest("check output (flatten $angle)", | |
| 2652 | - {$td->FILE => "a.pdf"}, | |
| 2653 | - {$td->FILE => "annotations-rotated-$angle.pdf"}); | |
| 2654 | -} | |
| 2655 | - | |
| 2656 | -# The file form-fields-and-annotations-shared.pdf contains some | |
| 2657 | -# annotations that appear in multiple pages /Annots, some non-shared | |
| 2658 | -# things that share appearance streams, some form fields appear on | |
| 2659 | -# multiple pages, and an indirect /Annotations array. It is out of | |
| 2660 | -# spec in several ways but still works in most viewers. These test | |
| 2661 | -# make sure we don't make anything worse and also end up exercising | |
| 2662 | -# some cases of things being copied more than once, though we also | |
| 2663 | -# exercise that with legitimate test cases using overlay. | |
| 2664 | - | |
| 2665 | -$td->runtest("shared annotations 1 page", | |
| 2666 | - {$td->COMMAND => | |
| 2667 | - "qpdf --qdf --no-original-object-ids --static-id" . | |
| 2668 | - " --rotate=90:1 form-fields-and-annotations-shared.pdf" . | |
| 2669 | - " a.pdf --flatten-rotation"}, | |
| 2670 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2671 | - $td->NORMALIZE_NEWLINES); | |
| 2672 | -$td->runtest("check output", | |
| 2673 | - {$td->FILE => "a.pdf"}, | |
| 2674 | - {$td->FILE => "rotated-shared-annotations-1.pdf"}); | |
| 2675 | -$td->runtest("shared annotations 2 pages", | |
| 2676 | - {$td->COMMAND => | |
| 2677 | - "qpdf --qdf --no-original-object-ids --static-id" . | |
| 2678 | - " --rotate=90:1,2 form-fields-and-annotations-shared.pdf" . | |
| 2679 | - " a.pdf --flatten-rotation"}, | |
| 2680 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2681 | - $td->NORMALIZE_NEWLINES); | |
| 2682 | -$td->runtest("check output", | |
| 2683 | - {$td->FILE => "a.pdf"}, | |
| 2684 | - {$td->FILE => "rotated-shared-annotations-2.pdf"}); | |
| 2685 | - | |
| 2686 | -show_ntests(); | |
| 2687 | -# ---------- | |
| 2688 | -$td->notify("--- Flatten Form/Annotations ---"); | |
| 2689 | - | |
| 2690 | -# manual-appearances was created by hand-coding appearance streams | |
| 2691 | -# with graphics that make it easy to test matrix calculations. The | |
| 2692 | -# result of flattening the annotations was compared visually with | |
| 2693 | -# okular. Some PDF viewers don't actually display the original version | |
| 2694 | -# correctly. The pages are as follows: | |
| 2695 | -# - page 1: normal | |
| 2696 | -# - page 2: rotate 90 with /F 20 (NoRotate) | |
| 2697 | -# - page 3: non-trivial matrix | |
| 2698 | -# - page 4: non-trivial matrix, rotate | |
| 2699 | -# - page 5: rotate 180 with /F 20 | |
| 2700 | -# - page 6: rotate 90, /F 20, non-trivial matrix | |
| 2701 | -# - page 7: flags: top is print, middle is screen, bottom is hidden | |
| 2702 | -# - page 8: rotate 270 with /F 20 | |
| 2703 | -# - page 9: normal -- available for additional testing | |
| 2704 | -# | |
| 2705 | -# form-filled-by-acrobat was filled in using the Acrobat Reader | |
| 2706 | -# android app. One of its appearance streams is actually an image. | |
| 2707 | -# | |
| 2708 | -# need-appearances.pdf is based on field-types.pdf with manual edits | |
| 2709 | -# to turn on NeedAppearances, change /V for several fields, and add | |
| 2710 | -# the comment annotation from comment-annotation.pdf. The test output | |
| 2711 | -# includes a flattened version of the comment annotation but not of | |
| 2712 | -# the form fields. Changes: | |
| 2713 | -# - field-types.pdf has /NeedAppearances true | |
| 2714 | -# - text1: blank -> abc | |
| 2715 | -# - r1: 1 -> 2 | |
| 2716 | -# - list1: blank -> five | |
| 2717 | -# - combolist1: blank -> pi | |
| 2718 | -# - drop1: blank -> elephant | |
| 2719 | -# - combodrop1: blank -> delta | |
| 2720 | - | |
| 2721 | -my @annotation_files = ( | |
| 2722 | - 'manual-appearances', | |
| 2723 | - 'form-filled-by-acrobat', | |
| 2724 | - 'comment-annotation', | |
| 2725 | - 'comment-annotation-direct', | |
| 2726 | - 'sample-form', | |
| 2727 | - 'need-appearances', | |
| 2728 | - 'need-appearances-more', | |
| 2729 | - ); | |
| 2730 | -$n_tests += 2 * scalar(@annotation_files); | |
| 2731 | - | |
| 2732 | -foreach my $f (@annotation_files) | |
| 2733 | -{ | |
| 2734 | - my $exp_out = {$td->STRING => "", $td->EXIT_STATUS => 0}; | |
| 2735 | - if (-f "$f-warn.out") | |
| 2736 | - { | |
| 2737 | - $exp_out = {$td->FILE => "$f-warn.out", $td->EXIT_STATUS => 3}; | |
| 2738 | - } | |
| 2739 | - $td->runtest("flatten $f", | |
| 2740 | - {$td->COMMAND => | |
| 2741 | - "qpdf --qdf --static-id --no-original-object-ids" . | |
| 2742 | - " --flatten-annotations=all $f.pdf a.pdf"}, | |
| 2743 | - $exp_out, | |
| 2744 | - $td->NORMALIZE_NEWLINES); | |
| 2745 | - $td->runtest("check output", | |
| 2746 | - {$td->FILE => "a.pdf"}, | |
| 2747 | - {$td->FILE => "$f-out.pdf"}); | |
| 2748 | -} | |
| 2749 | - | |
| 2750 | -$n_tests += 4; | |
| 2751 | -foreach my $f (qw(screen print)) | |
| 2752 | -{ | |
| 2753 | - $td->runtest("flatten for $f", | |
| 2754 | - {$td->COMMAND => | |
| 2755 | - "qpdf --qdf --static-id --no-original-object-ids" . | |
| 2756 | - " --flatten-annotations=$f manual-appearances.pdf a.pdf"}, | |
| 2757 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2758 | - $td->NORMALIZE_NEWLINES); | |
| 2759 | - $td->runtest("check output", | |
| 2760 | - {$td->FILE => "a.pdf"}, | |
| 2761 | - {$td->FILE => "manual-appearances-$f-out.pdf"}); | |
| 2762 | -} | |
| 2763 | - | |
| 2764 | -show_ntests(); | |
| 2765 | -# ---------- | |
| 2766 | -$td->notify("--- Copy Annotations ---"); | |
| 2767 | -$n_tests += 39; | |
| 2768 | - | |
| 2769 | -$td->runtest("complex copy annotations", | |
| 2770 | - {$td->COMMAND => | |
| 2771 | - "qpdf --qdf --static-id --no-original-object-ids" . | |
| 2772 | - " fxo-red.pdf --overlay form-fields-and-annotations.pdf" . | |
| 2773 | - " --repeat=1 -- a.pdf"}, | |
| 2774 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2775 | - $td->NORMALIZE_NEWLINES); | |
| 2776 | -$td->runtest("check output", | |
| 2777 | - {$td->FILE => "a.pdf"}, | |
| 2778 | - {$td->FILE => "overlay-copy-annotations.pdf"}); | |
| 2779 | - | |
| 2780 | -foreach my $page (1, 2, 5, 6) | |
| 2781 | -{ | |
| 2782 | - $td->runtest("copy annotations single page ($page)", | |
| 2783 | - {$td->COMMAND => | |
| 2784 | - "qpdf --qdf --static-id --no-original-object-ids" . | |
| 2785 | - " --pages . $page --" . | |
| 2786 | - " fxo-red.pdf --overlay form-fields-and-annotations.pdf" . | |
| 2787 | - " --repeat=1 -- a.pdf"}, | |
| 2788 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2789 | - $td->NORMALIZE_NEWLINES); | |
| 2790 | - $td->runtest("check output", | |
| 2791 | - {$td->FILE => "a.pdf"}, | |
| 2792 | - {$td->FILE => "overlay-copy-annotations-p$page.pdf"}); | |
| 2793 | -} | |
| 2794 | - | |
| 2795 | -foreach my $d ([1, "appearances-1.pdf"], | |
| 2796 | - [2, "appearances-1-rotated.pdf"]) | |
| 2797 | -{ | |
| 2798 | - my ($n, $file1) = @$d; | |
| 2799 | - $td->runtest("copy/transfer with defaults", | |
| 2800 | - {$td->COMMAND => "test_driver 80 $file1 minimal.pdf"}, | |
| 2801 | - {$td->STRING => "test 80 done\n", $td->EXIT_STATUS => 0}, | |
| 2802 | - $td->NORMALIZE_NEWLINES); | |
| 2803 | - $td->runtest("check output A", | |
| 2804 | - {$td->FILE => "a.pdf"}, | |
| 2805 | - {$td->FILE => "test80a$n.pdf"}); | |
| 2806 | - $td->runtest("check output B", | |
| 2807 | - {$td->FILE => "b.pdf"}, | |
| 2808 | - {$td->FILE => "test80b$n.pdf"}); | |
| 2809 | -} | |
| 2810 | - | |
| 2811 | -$td->runtest("page extraction with fields", | |
| 2812 | - {$td->COMMAND => | |
| 2813 | - "qpdf --static-id --empty" . | |
| 2814 | - " --pages fields-two-pages.pdf -- a.pdf"}, | |
| 2815 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2816 | - $td->NORMALIZE_NEWLINES); | |
| 2817 | -$td->runtest("check output", | |
| 2818 | - {$td->FILE => "a.pdf"}, | |
| 2819 | - {$td->FILE => "fields-pages-out.pdf"}); | |
| 2820 | -$td->runtest("page splitting with fields", | |
| 2821 | - {$td->COMMAND => | |
| 2822 | - "qpdf --static-id" . | |
| 2823 | - " --split-pages fields-two-pages.pdf split-out.pdf"}, | |
| 2824 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2825 | - $td->NORMALIZE_NEWLINES); | |
| 2826 | -for (my $i = 1; $i <= 2; ++$i) | |
| 2827 | -{ | |
| 2828 | - $td->runtest("check output", | |
| 2829 | - {$td->FILE => "split-out-$i.pdf"}, | |
| 2830 | - {$td->FILE => "fields-split-$i.pdf"}); | |
| 2831 | -} | |
| 2832 | -$td->runtest("keeping some fields", | |
| 2833 | - {$td->COMMAND => | |
| 2834 | - "qpdf --static-id fields-two-pages.pdf" . | |
| 2835 | - " --pages . 1 minimal.pdf -- a.pdf"}, | |
| 2836 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2837 | - $td->NORMALIZE_NEWLINES); | |
| 2838 | -$td->runtest("check output", | |
| 2839 | - {$td->FILE => "a.pdf"}, | |
| 2840 | - {$td->FILE => "kept-some-fields.pdf"}); | |
| 2841 | -$td->runtest("not keeping any fields", | |
| 2842 | - {$td->COMMAND => | |
| 2843 | - "qpdf --static-id kept-some-fields.pdf" . | |
| 2844 | - " --pages . 2 -- a.pdf"}, | |
| 2845 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2846 | - $td->NORMALIZE_NEWLINES); | |
| 2847 | -$td->runtest("check output", | |
| 2848 | - {$td->FILE => "a.pdf"}, | |
| 2849 | - {$td->FILE => "kept-no-fields.pdf"}); | |
| 2850 | -$td->runtest("other file first", | |
| 2851 | - {$td->COMMAND => | |
| 2852 | - "qpdf --qdf --no-original-object-ids" . | |
| 2853 | - " --static-id fields-two-pages.pdf" . | |
| 2854 | - " --pages ./fields-two-pages.pdf . 1 -- a.pdf"}, | |
| 2855 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2856 | - $td->NORMALIZE_NEWLINES); | |
| 2857 | -$td->runtest("check output", | |
| 2858 | - {$td->FILE => "a.pdf"}, | |
| 2859 | - {$td->FILE => "other-file-first.pdf"}); | |
| 2860 | - | |
| 2861 | -$td->runtest("field conflict resolution", | |
| 2862 | - {$td->COMMAND => | |
| 2863 | - "qpdf form-fields-and-annotations.pdf" . | |
| 2864 | - " --pages . 1,1 ./form-fields-and-annotations.pdf 1,1 --" . | |
| 2865 | - " --qdf --static-id --no-original-object-ids a.pdf"}, | |
| 2866 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2867 | - $td->NORMALIZE_NEWLINES); | |
| 2868 | -$td->runtest("check output", | |
| 2869 | - {$td->FILE => "a.pdf"}, | |
| 2870 | - {$td->FILE => "resolved-field-conflicts.pdf"}); | |
| 2871 | - | |
| 2872 | -# field-resource-conflict.pdf was crafted so that an appearance stream | |
| 2873 | -# had an existing resource that it actually referenced in the | |
| 2874 | -# appearance stream whose name, /F1_1, clashed with the result of | |
| 2875 | -# resolving conflicts in /DR. It's a crazy corner case, but it if it | |
| 2876 | -# ever happened, it would be really hard to track down, and it could | |
| 2877 | -# arise through multiple passes through qpdf with intervening edits. | |
| 2878 | -$td->runtest("appearance stream resource conflict", | |
| 2879 | - {$td->COMMAND => | |
| 2880 | - "qpdf field-resource-conflict.pdf" . | |
| 2881 | - " --pages . 1,1 ./field-resource-conflict.pdf --" . | |
| 2882 | - " --qdf --static-id --no-original-object-ids a.pdf"}, | |
| 2883 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2884 | - $td->NORMALIZE_NEWLINES); | |
| 2885 | -$td->runtest("check output", | |
| 2886 | - {$td->FILE => "a.pdf"}, | |
| 2887 | - {$td->FILE => "resolved-appearance-conflicts.pdf"}); | |
| 2888 | - | |
| 2889 | -$td->runtest("resource conflicts + flatten", | |
| 2890 | - {$td->COMMAND => | |
| 2891 | - "qpdf field-resource-conflict.pdf" . | |
| 2892 | - " --pages . 1,1 ./field-resource-conflict.pdf --" . | |
| 2893 | - " --generate-appearances --flatten-annotations=all" . | |
| 2894 | - " --qdf --static-id --no-original-object-ids a.pdf"}, | |
| 2895 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2896 | - $td->NORMALIZE_NEWLINES); | |
| 2897 | -$td->runtest("check output", | |
| 2898 | - {$td->FILE => "a.pdf"}, | |
| 2899 | - {$td->FILE => "resolved-appearance-conflicts-generate.pdf"}); | |
| 2900 | - | |
| 2901 | -$td->runtest("default DA/Q", | |
| 2902 | - {$td->COMMAND => | |
| 2903 | - "qpdf form-fields-and-annotations.pdf" . | |
| 2904 | - " --pages . default-da-q.pdf --" . | |
| 2905 | - " --qdf --static-id --no-original-object-ids" . | |
| 2906 | - " --generate-appearances a.pdf"}, | |
| 2907 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2908 | - $td->NORMALIZE_NEWLINES); | |
| 2909 | -$td->runtest("check output", | |
| 2910 | - {$td->FILE => "a.pdf"}, | |
| 2911 | - {$td->FILE => "default-da-q-out.pdf"}); | |
| 2912 | - | |
| 2913 | -$td->runtest("DA/appearance stream errors", | |
| 2914 | - {$td->COMMAND => | |
| 2915 | - "qpdf field-parse-errors.pdf" . | |
| 2916 | - " --pages ./field-parse-errors.pdf --" . | |
| 2917 | - " --qdf --static-id --no-original-object-ids a.pdf"}, | |
| 2918 | - {$td->FILE => "field-parse-errors.out", $td->EXIT_STATUS => 3}, | |
| 2919 | - $td->NORMALIZE_NEWLINES); | |
| 2920 | -$td->runtest("check output", | |
| 2921 | - {$td->FILE => "a.pdf"}, | |
| 2922 | - {$td->FILE => "field-parse-errors-out.pdf"}); | |
| 2923 | - | |
| 2924 | -$td->runtest("Direct DR and annotations", | |
| 2925 | - {$td->COMMAND => | |
| 2926 | - "qpdf direct-dr.pdf --split-pages" . | |
| 2927 | - " --qdf --static-id --no-original-object-ids" . | |
| 2928 | - " split-out.pdf"}, | |
| 2929 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2930 | - $td->NORMALIZE_NEWLINES); | |
| 2931 | -$td->runtest("check output", | |
| 2932 | - {$td->FILE => "split-out-1.pdf"}, | |
| 2933 | - {$td->FILE => "direct-dr-out.pdf"}); | |
| 2934 | - | |
| 2935 | -show_ntests(); | |
| 2936 | -# ---------- | |
| 2937 | -$td->notify("--- Page Tree Issues ---"); | |
| 2938 | -$n_tests += 11; | |
| 2939 | - | |
| 2940 | -$td->runtest("linearize duplicated pages", | |
| 2941 | - {$td->COMMAND => | |
| 2942 | - "qpdf --static-id --linearize" . | |
| 2943 | - " page_api_2.pdf a.pdf"}, | |
| 2944 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2945 | - $td->NORMALIZE_NEWLINES); | |
| 2946 | -$td->runtest("compare files", | |
| 2947 | - {$td->FILE => "a.pdf"}, | |
| 2948 | - {$td->FILE => "linearize-duplicate-page.pdf"}); | |
| 2949 | -$td->runtest("extract duplicated pages", | |
| 2950 | - {$td->COMMAND => | |
| 2951 | - "qpdf --static-id page_api_2.pdf" . | |
| 2952 | - " --pages . -- a.pdf"}, | |
| 2953 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2954 | - $td->NORMALIZE_NEWLINES); | |
| 2955 | -$td->runtest("compare files", | |
| 2956 | - {$td->FILE => "a.pdf"}, | |
| 2957 | - {$td->FILE => "extract-duplicate-page.pdf"}); | |
| 2958 | -$td->runtest("direct pages", | |
| 2959 | - {$td->COMMAND => | |
| 2960 | - "qpdf --static-id direct-pages.pdf --pages . -- a.pdf"}, | |
| 2961 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 2962 | - $td->NORMALIZE_NEWLINES); | |
| 2963 | -$td->runtest("check output", | |
| 2964 | - {$td->FILE => "a.pdf"}, | |
| 2965 | - {$td->FILE => "direct-pages-fixed.pdf"}); | |
| 2966 | -$td->runtest("show direct pages", | |
| 2967 | - {$td->COMMAND => | |
| 2968 | - "qpdf --show-pages direct-pages.pdf"}, | |
| 2969 | - {$td->FILE => "direct-pages.out", $td->EXIT_STATUS => 0}, | |
| 2970 | - $td->NORMALIZE_NEWLINES); | |
| 2971 | - | |
| 2972 | -# Json mode for direct and duplicated pages illustrates that the | |
| 2973 | -# "objects" section the original objects before correction when | |
| 2974 | -# "pages" is not output but after correct when it is.# numbers. | |
| 2975 | -foreach my $f (qw(page_api_2 direct-pages)) | |
| 2976 | -{ | |
| 2977 | - $td->runtest("json for $f (objects only)", | |
| 2978 | - {$td->COMMAND => | |
| 2979 | - "qpdf --json=latest $f.pdf" . | |
| 2980 | - " --json-key=qpdf"}, | |
| 2981 | - {$td->FILE => "$f-json-objects.out", $td->EXIT_STATUS => 0}, | |
| 2982 | - $td->NORMALIZE_NEWLINES); | |
| 2983 | - $td->runtest("json for $f (with pages)", | |
| 2984 | - {$td->COMMAND => | |
| 2985 | - "qpdf --json=latest $f.pdf" . | |
| 2986 | - " --json-key=qpdf --json-key=pages"}, | |
| 2987 | - {$td->FILE => "$f-json-pages.out", $td->EXIT_STATUS => 0}, | |
| 2988 | - $td->NORMALIZE_NEWLINES); | |
| 2989 | -} | |
| 2990 | - | |
| 2991 | -show_ntests(); | |
| 2992 | -# ---------- | |
| 2993 | -$td->notify("--- Merging and Splitting ---"); | |
| 2994 | -$n_tests += 28; | |
| 2995 | - | |
| 2996 | -# Select pages from the same file multiple times including selecting | |
| 2997 | -# twice from an encrypted file and specifying the password only the | |
| 2998 | -# first time. The file 20-pages.pdf is specified with two different | |
| 2999 | -# paths to duplicate a page. | |
| 3000 | -my $pages_options = "--pages page-labels-and-outlines.pdf 1,3,5-7,z" . | |
| 3001 | - " 20-pages.pdf --password=user z-15" . | |
| 3002 | - " page-labels-and-outlines.pdf 12" . | |
| 3003 | - " 20-pages.pdf 10" . | |
| 3004 | - " ./20-pages.pdf --password=owner 10" . | |
| 3005 | - " minimal.pdf 1 --"; | |
| 3006 | - | |
| 3007 | -$td->runtest("merge three files", | |
| 3008 | - {$td->COMMAND => "qpdf page-labels-and-outlines.pdf a.pdf" . | |
| 3009 | - " $pages_options --static-id --verbose --progress", | |
| 3010 | - $td->FILTER => "perl filter-progress.pl"}, | |
| 3011 | - {$td->FILE => "verbose-merge.out", $td->EXIT_STATUS => 0}, | |
| 3012 | - $td->NORMALIZE_NEWLINES); | |
| 3013 | -# Manually verified about this file: make sure that outline entries | |
| 3014 | -# that pointed to pages that were preserved still work in the copy, | |
| 3015 | -# and verify that all pages are as expected. page-labels-and-outlines | |
| 3016 | -# as well as 20-pages have text on page n (from 1) that shows its page | |
| 3017 | -# position from 0, so page 1 says it's page 0. | |
| 3018 | -$td->runtest("check output", | |
| 3019 | - {$td->FILE => "a.pdf"}, | |
| 3020 | - {$td->FILE => "merge-three-files-1.pdf"}); | |
| 3021 | -# Select the same pages but add them to an empty file | |
| 3022 | -$td->runtest("merge three files", | |
| 3023 | - {$td->COMMAND => "qpdf --empty a.pdf" . | |
| 3024 | - " $pages_options --static-id"}, | |
| 3025 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3026 | -# Manually verified about this file: it has the same pages but does | |
| 3027 | -# not contain outlines or other things from the original file. | |
| 3028 | -$td->runtest("check output", | |
| 3029 | - {$td->FILE => "a.pdf"}, | |
| 3030 | - {$td->FILE => "merge-three-files-2.pdf"}); | |
| 3031 | -$td->runtest("avoid respecification of password", | |
| 3032 | - {$td->COMMAND => | |
| 3033 | - "qpdf --empty a.pdf --copy-encryption=20-pages.pdf" . | |
| 3034 | - " --allow-weak-crypto" . | |
| 3035 | - " --encryption-file-password=user" . | |
| 3036 | - " --pages 20-pages.pdf 1,z -- --static-id"}, | |
| 3037 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3038 | -$td->runtest("check output", | |
| 3039 | - {$td->FILE => "a.pdf"}, | |
| 3040 | - {$td->FILE => "pages-copy-encryption.pdf"}); | |
| 3041 | -$td->runtest("merge with implicit ranges", | |
| 3042 | - {$td->COMMAND => | |
| 3043 | - "qpdf --empty a.pdf" . | |
| 3044 | - " --pages minimal.pdf 20-pages.pdf --password=user" . | |
| 3045 | - " page-labels-and-outlines.pdf --" . | |
| 3046 | - " --static-id"}, | |
| 3047 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3048 | -$td->runtest("check output", | |
| 3049 | - {$td->FILE => "a.pdf"}, | |
| 3050 | - {$td->FILE => "merge-implicit-ranges.pdf"}); | |
| 3051 | -$td->runtest("merge with . and implicit ranges", | |
| 3052 | - {$td->COMMAND => | |
| 3053 | - "qpdf minimal.pdf a.pdf --pages minimal.pdf . 1 --" . | |
| 3054 | - " --static-id"}, | |
| 3055 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3056 | -$td->runtest("check output", | |
| 3057 | - {$td->FILE => "a.pdf"}, | |
| 3058 | - {$td->FILE => "merge-dot-implicit-ranges.pdf"}); | |
| 3059 | -$td->runtest("merge with multiple labels", | |
| 3060 | - {$td->COMMAND => | |
| 3061 | - "qpdf --empty a.pdf" . | |
| 3062 | - " --pages 11-pages-with-labels.pdf 8-11" . | |
| 3063 | - " minimal.pdf " . | |
| 3064 | - " page-labels-and-outlines.pdf 17-19 --" . | |
| 3065 | - " --static-id"}, | |
| 3066 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3067 | -$td->runtest("check output", | |
| 3068 | - {$td->FILE => "a.pdf"}, | |
| 3069 | - {$td->FILE => "merge-multiple-labels.pdf"}); | |
| 3070 | -$td->runtest("remove labels", | |
| 3071 | - {$td->COMMAND => | |
| 3072 | - "qpdf --empty a.pdf" . | |
| 3073 | - " --remove-page-labels" . | |
| 3074 | - " --pages 11-pages-with-labels.pdf 8-11" . | |
| 3075 | - " minimal.pdf " . | |
| 3076 | - " page-labels-and-outlines.pdf 17-19 --" . | |
| 3077 | - " --static-id"}, | |
| 3078 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3079 | -$td->runtest("check output", | |
| 3080 | - {$td->FILE => "a.pdf"}, | |
| 3081 | - {$td->FILE => "remove-labels.pdf"}); | |
| 3082 | - | |
| 3083 | -$td->runtest("split with shared resources", | |
| 3084 | - {$td->COMMAND => | |
| 3085 | - "qpdf --qdf --static-id" . | |
| 3086 | - " --remove-unreferenced-resources=yes" . | |
| 3087 | - " shared-images.pdf --pages . 1,3" . | |
| 3088 | - " ./shared-images.pdf 1,2 -- a.pdf"}, | |
| 3089 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3090 | -$td->runtest("check output", | |
| 3091 | - {$td->FILE => "a.pdf"}, | |
| 3092 | - {$td->FILE => "shared-images-pages-out.pdf"}); | |
| 3093 | - | |
| 3094 | -$td->runtest("split with really shared resources", | |
| 3095 | - {$td->COMMAND => | |
| 3096 | - "qpdf --qdf --static-id" . | |
| 3097 | - " --remove-unreferenced-resources=yes" . | |
| 3098 | - " shared-images.pdf --pages . 1,3" . | |
| 3099 | - " . 1,2 -- a.pdf"}, | |
| 3100 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3101 | -$td->runtest("check output", | |
| 3102 | - {$td->FILE => "a.pdf"}, | |
| 3103 | - {$td->FILE => "really-shared-images-pages-out.pdf"}); | |
| 3104 | - | |
| 3105 | -$td->runtest("shared resources relevant errors", | |
| 3106 | - {$td->COMMAND => | |
| 3107 | - "qpdf --qdf --static-id" . | |
| 3108 | - " shared-images-errors.pdf --pages . 2 -- a.pdf"}, | |
| 3109 | - {$td->FILE => "shared-images-errors-2.out", | |
| 3110 | - $td->EXIT_STATUS => 3}, | |
| 3111 | - $td->NORMALIZE_NEWLINES); | |
| 3112 | -$td->runtest("check output", | |
| 3113 | - {$td->FILE => "a.pdf"}, | |
| 3114 | - {$td->FILE => "shared-images-errors-2-out.pdf"}); | |
| 3115 | - | |
| 3116 | -# This test used to generate warnings about images on pages we didn't | |
| 3117 | -# care about, but qpdf was modified not to process those pages, so the | |
| 3118 | -# "irrelevant" errors went away. | |
| 3119 | -$td->runtest("shared resources irrelevant errors", | |
| 3120 | - {$td->COMMAND => | |
| 3121 | - "qpdf --qdf --static-id" . | |
| 3122 | - " shared-images-errors.pdf --pages . 1 -- a.pdf"}, | |
| 3123 | - {$td->STRING => "", | |
| 3124 | - $td->EXIT_STATUS => 0}, | |
| 3125 | - $td->NORMALIZE_NEWLINES); | |
| 3126 | -$td->runtest("check output", | |
| 3127 | - {$td->FILE => "a.pdf"}, | |
| 3128 | - {$td->FILE => "shared-images-errors-1-out.pdf"}); | |
| 3129 | - | |
| 3130 | -$td->runtest("don't remove shared resources", | |
| 3131 | - {$td->COMMAND => | |
| 3132 | - "qpdf --qdf --static-id --preserve-unreferenced-resources" . | |
| 3133 | - " shared-images.pdf --pages . 1,3 -- a.pdf"}, | |
| 3134 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3135 | -$td->runtest("check output", | |
| 3136 | - {$td->FILE => "a.pdf"}, | |
| 3137 | - {$td->FILE => "shared-images-errors-1-3-out.pdf"}); | |
| 3138 | - | |
| 3139 | -$td->runtest("duplicate pages", | |
| 3140 | - {$td->COMMAND => | |
| 3141 | - "qpdf --qdf --static-id 11-pages-with-labels.pdf" . | |
| 3142 | - " --pages . 6,5,6 . 5 minimal.pdf 1,1 minimal.pdf 1 --" . | |
| 3143 | - " a.pdf"}, | |
| 3144 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3145 | -$td->runtest("check output", | |
| 3146 | - {$td->FILE => "a.pdf"}, | |
| 3147 | - {$td->FILE => "duplicate-pages.pdf"}); | |
| 3148 | - | |
| 3149 | -# See https://github.com/qpdf/qpdf/issues/399 -- we don't want to | |
| 3150 | -# break this, especially if we ever implement deduplication of | |
| 3151 | -# identical streams. | |
| 3152 | -$td->runtest("force full page duplication", | |
| 3153 | - {$td->COMMAND => "qpdf --static-id minimal.pdf" . | |
| 3154 | - " --pages . ./minimal.pdf -- a.pdf"}, | |
| 3155 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 3156 | - $td->NORMALIZE_NEWLINES); | |
| 3157 | -$td->runtest("check output", | |
| 3158 | - {$td->FILE => "a.pdf"}, | |
| 3159 | - {$td->FILE => "deep-duplicate-pages.pdf"}); | |
| 3160 | - | |
| 3161 | - | |
| 3162 | -show_ntests(); | |
| 3163 | -# ---------- | |
| 3164 | -$td->notify("--- Collating ---"); | |
| 3165 | -my @collate = ( | |
| 3166 | - ["", "three-files", "collate-odd", | |
| 3167 | - "collate-odd.pdf 1-5 minimal.pdf collate-even.pdf 7-1"], | |
| 3168 | - [1, "three-files", "collate-odd", | |
| 3169 | - "collate-odd.pdf 1-5 minimal.pdf collate-even.pdf 7-1"], | |
| 3170 | - [2, "three-files-2", "collate-odd", | |
| 3171 | - "collate-odd.pdf 1-5 minimal.pdf collate-even.pdf 7-1"], | |
| 3172 | - ); | |
| 3173 | -$n_tests += 2 * scalar(@collate); | |
| 3174 | - | |
| 3175 | -foreach my $d (@collate) | |
| 3176 | -{ | |
| 3177 | - my ($n, $description, $first, $args) = @$d; | |
| 3178 | - my $collate = '--collate'; | |
| 3179 | - if ($n) | |
| 3180 | - { | |
| 3181 | - $collate .= "=$n"; | |
| 3182 | - } | |
| 3183 | - $td->runtest("collate pages: $description", | |
| 3184 | - {$td->COMMAND => | |
| 3185 | - "qpdf --qdf --static-id $collate $first.pdf" . | |
| 3186 | - " --pages $args -- a.pdf"}, | |
| 3187 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3188 | - $td->runtest("check output", | |
| 3189 | - {$td->FILE => "a.pdf"}, | |
| 3190 | - {$td->FILE => "$description-collate-out.pdf"}); | |
| 3191 | -} | |
| 3192 | - | |
| 3193 | -show_ntests(); | |
| 3194 | -# ---------- | |
| 3195 | -$td->notify("--- PDF From Scratch ---"); | |
| 3196 | -$n_tests += 2; | |
| 3197 | - | |
| 3198 | -$td->runtest("basic qpdf from scratch", | |
| 3199 | - {$td->COMMAND => "pdf_from_scratch 0"}, | |
| 3200 | - {$td->STRING => "test 0 done\n", $td->EXIT_STATUS => 0}, | |
| 3201 | - $td->NORMALIZE_NEWLINES); | |
| 3202 | -$td->runtest("check output", | |
| 3203 | - {$td->FILE => "a.pdf"}, | |
| 3204 | - {$td->FILE => "from-scratch-0.pdf"}); | |
| 3205 | -show_ntests(); | |
| 3206 | -# ---------- | |
| 3207 | -$td->notify("--- PCLm ---"); | |
| 3208 | -$n_tests += 2; | |
| 3209 | - | |
| 3210 | -$td->runtest("write as PCLm", | |
| 3211 | - {$td->COMMAND => "test_driver 40 pclm-in.pdf a.pdf"}, | |
| 3212 | - {$td->STRING => "test 40 done\n", $td->EXIT_STATUS => 0}, | |
| 3213 | - $td->NORMALIZE_NEWLINES); | |
| 3214 | -$td->runtest("check output", | |
| 3215 | - {$td->FILE => "a.pdf"}, | |
| 3216 | - {$td->FILE => "pclm-out.pdf"}); | |
| 3217 | - | |
| 3218 | -show_ntests(); | |
| 3219 | -# ---------- | |
| 3220 | -$td->notify("--- Precheck streams ---"); | |
| 3221 | -$n_tests += 2; | |
| 3222 | - | |
| 3223 | -$td->runtest("bad stream", | |
| 3224 | - {$td->COMMAND => "qpdf --static-id bad-data.pdf a.pdf"}, | |
| 3225 | - {$td->FILE => "bad-data.out", $td->EXIT_STATUS => 3}, | |
| 3226 | - $td->NORMALIZE_NEWLINES); | |
| 3227 | -$td->runtest("check output", | |
| 3228 | - {$td->FILE => "a.pdf"}, | |
| 3229 | - {$td->FILE => "bad-data-out.pdf"}); | |
| 3230 | - | |
| 3231 | -show_ntests(); | |
| 3232 | -# ---------- | |
| 3233 | -$td->notify("--- Decode levels ---"); | |
| 3234 | -$n_tests += 14; | |
| 3235 | - | |
| 3236 | -# image-streams.pdf is the output of examples/pdf-create. | |
| 3237 | -# examples/pdf-create validates the actual image data. | |
| 3238 | -# image-streams-small.pdf was manually created by editing | |
| 3239 | -# pdf-create.cc to reduce width and height to 40x8 and ignoring | |
| 3240 | -# errors. Its purpose was to get a small file with images with | |
| 3241 | -# different filters for fuzz testing. | |
| 3242 | -foreach my $l (qw(none generalized specialized all)) | |
| 3243 | -{ | |
| 3244 | - $td->runtest("image-streams: $l", | |
| 3245 | - {$td->COMMAND => | |
| 3246 | - "qpdf image-streams.pdf --compress-streams=n" . | |
| 3247 | - " --decode-level=$l a.pdf"}, | |
| 3248 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 3249 | - $td->NORMALIZE_NEWLINES); | |
| 3250 | - $td->runtest("check image-streams: $l", | |
| 3251 | - {$td->COMMAND => "test_driver 39 a.pdf"}, | |
| 3252 | - {$td->FILE => "image-streams-$l.out", $td->EXIT_STATUS => 0}, | |
| 3253 | - $td->NORMALIZE_NEWLINES); | |
| 3254 | -} | |
| 3255 | - | |
| 3256 | -# C API | |
| 3257 | -$td->runtest("image-streams: C", | |
| 3258 | - {$td->COMMAND => "qpdf-ctest 20 image-streams.pdf '' a.pdf"}, | |
| 3259 | - {$td->STRING => "C test 20 done\n", $td->EXIT_STATUS => 0}, | |
| 3260 | - $td->NORMALIZE_NEWLINES); | |
| 3261 | -$td->runtest("check image-streams: C", | |
| 3262 | - {$td->COMMAND => "test_driver 39 a.pdf"}, | |
| 3263 | - {$td->FILE => "image-streams-specialized.out", | |
| 3264 | - $td->EXIT_STATUS => 0}, | |
| 3265 | - $td->NORMALIZE_NEWLINES); | |
| 3266 | - | |
| 3267 | -# Bad JPEG data | |
| 3268 | -$td->runtest("check finds bad jpeg data", | |
| 3269 | - {$td->COMMAND => "qpdf --check bad-jpeg.pdf"}, | |
| 3270 | - {$td->FILE => "bad-jpeg-check.out", | |
| 3271 | - $td->EXIT_STATUS => 3}, | |
| 3272 | - $td->NORMALIZE_NEWLINES); | |
| 3273 | -$td->runtest("precheck detects bad jpeg data", | |
| 3274 | - {$td->COMMAND => "qpdf --static-id --decode-level=all" . | |
| 3275 | - " bad-jpeg.pdf a.pdf"}, | |
| 3276 | - {$td->FILE => "bad-jpeg.out", $td->EXIT_STATUS => 3}, | |
| 3277 | - $td->NORMALIZE_NEWLINES); | |
| 3278 | -$td->runtest("check file", | |
| 3279 | - {$td->FILE => "a.pdf"}, | |
| 3280 | - {$td->FILE => "bad-jpeg-out.pdf"}); | |
| 3281 | -$td->runtest("get data", | |
| 3282 | - {$td->COMMAND => "qpdf --show-object=6" . | |
| 3283 | - " --filtered-stream-data bad-jpeg.pdf"}, | |
| 3284 | - {$td->FILE => "bad-jpeg-show.out", $td->EXIT_STATUS => 3}, | |
| 3285 | - $td->NORMALIZE_NEWLINES); | |
| 3286 | - | |
| 3287 | -show_ntests(); | |
| 3288 | -# ---------- | |
| 3289 | -$td->notify("--- Image Optimization ---"); | |
| 3290 | -my @image_opt = ( | |
| 3291 | - ['image-streams', 'image-streams', ''], | |
| 3292 | - ['small-images', 'defaults', ''], | |
| 3293 | - ['small-images', 'min-width', | |
| 3294 | - '--oi-min-width=150 --oi-min-height=0 --oi-min-area=0'], | |
| 3295 | - ['small-images', 'min-height', | |
| 3296 | - '--oi-min-width=0 --oi-min-height=150 --oi-min-area=0'], | |
| 3297 | - ['small-images', 'min-area', | |
| 3298 | - '--oi-min-width=0 --oi-min-height=0 --oi-min-area=30000'], | |
| 3299 | - ['small-images', 'min-area-all', | |
| 3300 | - '--oi-min-width=0 --oi-min-height=0 --oi-min-area=30000'], | |
| 3301 | - ['large-inline-image', 'inline-images', | |
| 3302 | - '--ii-min-bytes=0'], | |
| 3303 | - ['large-inline-image', 'inline-images-all-size', | |
| 3304 | - '--oi-min-width=0 --oi-min-height=0 --oi-min-area=0 --ii-min-bytes=0'], | |
| 3305 | - ['large-inline-image', 'inline-images-keep-some', ''], | |
| 3306 | - ['large-inline-image', 'inline-images-keep-all', '--keep-inline-images'], | |
| 3307 | - ['unsupported-optimization', 'unsupported', | |
| 3308 | - '--oi-min-width=0 --oi-min-height=0 --oi-min-area=0'], | |
| 3309 | - ); | |
| 3310 | - | |
| 3311 | -$n_tests += 2 * scalar(@image_opt); | |
| 3312 | - | |
| 3313 | -foreach my $d (@image_opt) | |
| 3314 | -{ | |
| 3315 | - my ($f, $description, $args) = @$d; | |
| 3316 | - | |
| 3317 | - $td->runtest("optimize images: $description", | |
| 3318 | - {$td->COMMAND => | |
| 3319 | - "qpdf --static-id --optimize-images --verbose" . | |
| 3320 | - " $args $f.pdf a.pdf", | |
| 3321 | - $td->FILTER => "perl filter-optimize-images.pl"}, | |
| 3322 | - {$td->FILE => "optimize-images-$description.out", | |
| 3323 | - $td->EXIT_STATUS => 0}, | |
| 3324 | - $td->NORMALIZE_NEWLINES); | |
| 3325 | - $td->runtest("check json: $description", | |
| 3326 | - {$td->COMMAND => "qpdf --json --json-key=pages a.pdf"}, | |
| 3327 | - {$td->FILE => "optimize-images-$description-json.out", | |
| 3328 | - $td->EXIT_STATUS => 0}, | |
| 3329 | - $td->NORMALIZE_NEWLINES); | |
| 3330 | -} | |
| 3331 | - | |
| 3332 | -show_ntests(); | |
| 3333 | -# ---------- | |
| 3334 | -$td->notify("--- Preserve unreferenced objects ---"); | |
| 3335 | -$n_tests += 6; | |
| 3336 | - | |
| 3337 | -$td->runtest("drop unused objects", | |
| 3338 | - {$td->COMMAND => "qpdf --static-id unreferenced-objects.pdf a.pdf"}, | |
| 3339 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3340 | -$td->runtest("check output", | |
| 3341 | - {$td->FILE => "a.pdf"}, | |
| 3342 | - {$td->FILE => "unreferenced-dropped.pdf"}); | |
| 3343 | -$td->runtest("keep unused objects", | |
| 3344 | - {$td->COMMAND => "qpdf --static-id --preserve-unreferenced" . | |
| 3345 | - " unreferenced-objects.pdf a.pdf"}, | |
| 3346 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3347 | -$td->runtest("check output", | |
| 3348 | - {$td->FILE => "a.pdf"}, | |
| 3349 | - {$td->FILE => "unreferenced-preserved.pdf"}); | |
| 3350 | -$td->runtest("keep unused objects (C)", | |
| 3351 | - {$td->COMMAND => | |
| 3352 | - "qpdf-ctest 21 unreferenced-objects.pdf '' a.pdf"}, | |
| 3353 | - {$td->STRING => "C test 21 done\n", $td->EXIT_STATUS => 0}, | |
| 3354 | - $td->NORMALIZE_NEWLINES); | |
| 3355 | -$td->runtest("check output", | |
| 3356 | - {$td->FILE => "a.pdf"}, | |
| 3357 | - {$td->FILE => "unreferenced-preserved.pdf"}); | |
| 3358 | -show_ntests(); | |
| 3359 | -# ---------- | |
| 3360 | -$td->notify("--- Copy Foreign Objects ---"); | |
| 3361 | -$n_tests += 11; | |
| 3362 | - | |
| 3363 | -foreach my $d ([25, 1], [26, 2], [27, 3]) | |
| 3364 | -{ | |
| 3365 | - my ($testn, $outn) = @$d; | |
| 3366 | - $td->runtest("copy objects $outn", | |
| 3367 | - {$td->COMMAND => "test_driver $testn" . | |
| 3368 | - " minimal.pdf copy-foreign-objects-in.pdf"}, | |
| 3369 | - {$td->FILE => "copy-foreign-objects-$testn.out", | |
| 3370 | - $td->EXIT_STATUS => 0}, | |
| 3371 | - $td->NORMALIZE_NEWLINES); | |
| 3372 | - $td->runtest("check output", | |
| 3373 | - {$td->FILE => "a.pdf"}, | |
| 3374 | - {$td->FILE => "copy-foreign-objects-out$outn.pdf"}); | |
| 3375 | -} | |
| 3376 | -$td->runtest("copy objects error", | |
| 3377 | - {$td->COMMAND => "test_driver 28" . | |
| 3378 | - " copy-foreign-objects-in.pdf minimal.pdf"}, | |
| 3379 | - {$td->FILE => "copy-foreign-objects-errors.out", | |
| 3380 | - $td->EXIT_STATUS => 0}, | |
| 3381 | - $td->NORMALIZE_NEWLINES); | |
| 3382 | - | |
| 3383 | -# Issue 449 involved indirect /Filter or /DecodeParms in streams that | |
| 3384 | -# had their stream data replaced. The hand-generated | |
| 3385 | -# indirect-filter.pdf file more or less reproduces the situation but | |
| 3386 | -# doesn't result in the same internal error that 449 did with 10.0.1. | |
| 3387 | -# The file issue-449.pdf was minimized by hand from a test case and | |
| 3388 | -# does produce an internal error, though the exact reason is unclear. | |
| 3389 | -# It seems to just have to do with the order in which things are | |
| 3390 | -# copied. | |
| 3391 | -$td->runtest("indirect filters", | |
| 3392 | - {$td->COMMAND => "test_driver 69 indirect-filter.pdf"}, | |
| 3393 | - {$td->STRING => "test 69 done\n", $td->EXIT_STATUS => 0}, | |
| 3394 | - $td->NORMALIZE_NEWLINES); | |
| 3395 | -foreach my $i (0, 1) | |
| 3396 | -{ | |
| 3397 | - $td->runtest("check output", | |
| 3398 | - {$td->FILE => "auto-$i.pdf"}, | |
| 3399 | - {$td->FILE => "indirect-filter-out-$i.pdf"}); | |
| 3400 | -} | |
| 3401 | -$td->runtest("issue 449", | |
| 3402 | - {$td->COMMAND => "test_driver 69 issue-449.pdf"}, | |
| 3403 | - {$td->STRING => "test 69 done\n", $td->EXIT_STATUS => 0}, | |
| 3404 | - $td->NORMALIZE_NEWLINES); | |
| 3405 | - | |
| 3406 | -show_ntests(); | |
| 3407 | -# ---------- | |
| 3408 | -$td->notify("--- Error Condition Tests ---"); | |
| 3409 | -# $n_tests incremented after initialization of badfiles below. | |
| 3410 | - | |
| 3411 | -my @badfiles = ("not a PDF file", # 1 | |
| 3412 | - "no startxref", # 2 | |
| 3413 | - "bad primary xref offset", # 3 | |
| 3414 | - "invalid xref syntax", # 4 | |
| 3415 | - "invalid xref entry", # 5 | |
| 3416 | - "free table inconsistency", # 6 | |
| 3417 | - "no trailer dictionary", # 7 | |
| 3418 | - "bad secondary xref", # 8 | |
| 3419 | - "no /Size in trailer", # 9 | |
| 3420 | - "/Size not integer", # 10 | |
| 3421 | - "/Prev not integer", # 11 | |
| 3422 | - "/Size inconsistency", # 12 | |
| 3423 | - "bad {", # 13 | |
| 3424 | - "bad }", # 14 | |
| 3425 | - "bad ]", # 15 | |
| 3426 | - "bad >>", # 16 | |
| 3427 | - "dictionary errors", # 17 | |
| 3428 | - "bad )", # 18 | |
| 3429 | - "bad >", # 19 | |
| 3430 | - "invalid hexstring character", # 20 | |
| 3431 | - "invalid name token", # 21 | |
| 3432 | - "no /Length for stream dictionary", # 22 | |
| 3433 | - "/Length not integer", # 23 | |
| 3434 | - "expected endstream", # 24 | |
| 3435 | - "bad obj declaration (objid)", # 25 | |
| 3436 | - "bad obj declaration (generation)", # 26 | |
| 3437 | - "bad obj declaration (obj)", # 27 | |
| 3438 | - "expected endobj", # 28 | |
| 3439 | - "null in name", # 29 | |
| 3440 | - "invalid stream /Filter", # 30 | |
| 3441 | - "unknown stream /Filter", # 31 | |
| 3442 | - "obj/gen mismatch", # 32 | |
| 3443 | - "invalid stream /Filter and xref", # 33 | |
| 3444 | - "obj/gen in wrong place", # 34 | |
| 3445 | - "object stream of wrong type", # 35 | |
| 3446 | - "bad dictionary key", # 36 | |
| 3447 | - "space before xref", # 37 | |
| 3448 | - "startxref to space then eof", # 38 | |
| 3449 | - ); | |
| 3450 | - | |
| 3451 | -$n_tests += @badfiles + 8; | |
| 3452 | - | |
| 3453 | -# Test 6 contains errors in the free table consistency, but we no | |
| 3454 | -# longer have any consistency check for this since it is not important | |
| 3455 | -# neither Acrobat nor other PDF viewers really care. Tests 12 and 28 | |
| 3456 | -# have error conditions that used to be fatal but are now considered | |
| 3457 | -# non-fatal. | |
| 3458 | -my %badtest_overrides = (); | |
| 3459 | -for(6, 12..15, 17, 18..32, 34..37) | |
| 3460 | -{ | |
| 3461 | - $badtest_overrides{$_} = 0; | |
| 3462 | -} | |
| 3463 | - | |
| 3464 | -for (my $i = 1; $i <= scalar(@badfiles); ++$i) | |
| 3465 | -{ | |
| 3466 | - my $status = $badtest_overrides{$i}; | |
| 3467 | - $status = 2 unless defined $status; | |
| 3468 | - $td->runtest($badfiles[$i-1], | |
| 3469 | - {$td->COMMAND => "test_driver 0 bad$i.pdf"}, | |
| 3470 | - {$td->FILE => "bad$i.out", | |
| 3471 | - $td->EXIT_STATUS => $status}, | |
| 3472 | - $td->NORMALIZE_NEWLINES); | |
| 3473 | -} | |
| 3474 | - | |
| 3475 | -$td->runtest("Suppress warnings", | |
| 3476 | - {$td->COMMAND => "qpdf --no-warn bad14.pdf a.pdf"}, | |
| 3477 | - {$td->STRING => "", $td->EXIT_STATUS => 3}); | |
| 3478 | -$td->runtest("Suppress warnings", | |
| 3479 | - {$td->COMMAND => | |
| 3480 | - "qpdf --no-warn --warning-exit-0 bad14.pdf a.pdf"}, | |
| 3481 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3482 | -$td->runtest("Suppress warnings with --check", | |
| 3483 | - {$td->COMMAND => "qpdf --check --no-warn bad14.pdf"}, | |
| 3484 | - {$td->FILE => "bad14-check-no-warn.out", | |
| 3485 | - $td->EXIT_STATUS => 3}, | |
| 3486 | - $td->NORMALIZE_NEWLINES); | |
| 3487 | -$td->runtest("C API: errors", | |
| 3488 | - {$td->COMMAND => "qpdf-ctest 2 bad1.pdf '' a.pdf"}, | |
| 3489 | - {$td->FILE => "c-read-errors.out", | |
| 3490 | - $td->EXIT_STATUS => 0}, | |
| 3491 | - $td->NORMALIZE_NEWLINES); | |
| 3492 | -$td->runtest("C API: warnings writing", | |
| 3493 | - {$td->COMMAND => "qpdf-ctest 2 bad33.pdf '' a.pdf"}, | |
| 3494 | - {$td->FILE => "c-write-warnings.out", | |
| 3495 | - $td->EXIT_STATUS => 0}, | |
| 3496 | - $td->NORMALIZE_NEWLINES); | |
| 3497 | -$td->runtest("C API: no recovery", | |
| 3498 | - {$td->COMMAND => "qpdf-ctest 10 bad33.pdf '' a.pdf"}, | |
| 3499 | - {$td->FILE => "c-no-recovery.out", | |
| 3500 | - $td->EXIT_STATUS => 0}, | |
| 3501 | - $td->NORMALIZE_NEWLINES); | |
| 3502 | - | |
| 3503 | -$td->runtest("integer type checks", | |
| 3504 | - {$td->COMMAND => "test_driver 62 minimal.pdf"}, | |
| 3505 | - {$td->STRING => "test 62 done\n", $td->EXIT_STATUS => 0}, | |
| 3506 | - $td->NORMALIZE_NEWLINES); | |
| 3507 | -$td->runtest("getValueAs... accessor checks", | |
| 3508 | - {$td->COMMAND => "test_driver 85 -"}, | |
| 3509 | - {$td->STRING => "test 85 done\n", $td->EXIT_STATUS => 0}, | |
| 3510 | - $td->NORMALIZE_NEWLINES); | |
| 3511 | - | |
| 3512 | -show_ntests(); | |
| 3513 | -# ---------- | |
| 3514 | -$td->notify("--- Recovery Tests ---"); | |
| 3515 | -$n_tests += @badfiles + 11; | |
| 3516 | - | |
| 3517 | -# Recovery tests. These are mostly after-the-fact -- when recovery | |
| 3518 | -# was implemented, some degree of recovery was possible on many of the | |
| 3519 | -# files. Mostly the recovery does not actually repair the error, | |
| 3520 | -# though in some cases it may. Acrobat Reader would not be able to | |
| 3521 | -# recover any of these files any better. | |
| 3522 | -my %recover_failures = (); | |
| 3523 | -for (1, 7, 16) | |
| 3524 | -{ | |
| 3525 | - $recover_failures{$_} = 1; | |
| 3526 | -} | |
| 3527 | -for (my $i = 1; $i <= scalar(@badfiles); ++$i) | |
| 3528 | -{ | |
| 3529 | - my $status = 0; | |
| 3530 | - if (exists $recover_failures{$i}) | |
| 3531 | - { | |
| 3532 | - $status = 2; | |
| 3533 | - } | |
| 3534 | - $td->runtest("recover " . $badfiles[$i-1], | |
| 3535 | - {$td->COMMAND => "test_driver 1 bad$i.pdf"}, | |
| 3536 | - {$td->FILE => "bad$i-recover.out", | |
| 3537 | - $td->EXIT_STATUS => $status}, | |
| 3538 | - $td->NORMALIZE_NEWLINES); | |
| 3539 | -} | |
| 3540 | - | |
| 3541 | -# See if we can recover the cross reference table on a file that has | |
| 3542 | -# been appended to even when it deletes and reuses objects. We can't | |
| 3543 | -# completely do it in the case of deleted objects, but we can get | |
| 3544 | -# mostly there. | |
| 3545 | -$td->runtest("good replaced page contents", | |
| 3546 | - {$td->COMMAND => | |
| 3547 | - "qpdf --static-id -qdf --no-original-object-ids" . | |
| 3548 | - " append-page-content.pdf a.pdf"}, | |
| 3549 | - {$td->STRING => "", | |
| 3550 | - $td->EXIT_STATUS => 0}, | |
| 3551 | - $td->NORMALIZE_NEWLINES); | |
| 3552 | -$td->runtest("check output", | |
| 3553 | - {$td->FILE => "a.pdf"}, | |
| 3554 | - {$td->FILE => "append-page-content-good.qdf"}); | |
| 3555 | -$td->runtest("damaged replaced page contents", | |
| 3556 | - {$td->COMMAND => | |
| 3557 | - "qpdf --static-id -qdf --no-original-object-ids" . | |
| 3558 | - " append-page-content-damaged.pdf a.pdf"}, | |
| 3559 | - {$td->FILE => "append-page-content-damaged.out", | |
| 3560 | - $td->EXIT_STATUS => 3}, | |
| 3561 | - $td->NORMALIZE_NEWLINES); | |
| 3562 | -$td->runtest("check output", | |
| 3563 | - {$td->FILE => "a.pdf"}, | |
| 3564 | - {$td->FILE => "append-page-content-damaged.qdf"}); | |
| 3565 | -$td->runtest("run check on damaged file", | |
| 3566 | - {$td->COMMAND => "qpdf --check append-page-content-damaged.pdf"}, | |
| 3567 | - {$td->FILE => "append-page-content-damaged-check.out", | |
| 3568 | - $td->EXIT_STATUS => 3}, | |
| 3569 | - $td->NORMALIZE_NEWLINES); | |
| 3570 | -$td->runtest("check with C API", | |
| 3571 | - {$td->COMMAND => | |
| 3572 | - "qpdf-ctest 1 append-page-content-damaged.pdf '' ''"}, | |
| 3573 | - {$td->FILE => "append-page-content-damaged-c-check.out", | |
| 3574 | - $td->EXIT_STATUS => 0}, | |
| 3575 | - $td->NORMALIZE_NEWLINES); | |
| 3576 | - | |
| 3577 | -$td->runtest("recoverable xref errors", | |
| 3578 | - {$td->COMMAND => | |
| 3579 | - "qpdf --check --show-xref xref-errors.pdf"}, | |
| 3580 | - {$td->FILE => "xref-errors.out", | |
| 3581 | - $td->EXIT_STATUS => 3}, | |
| 3582 | - $td->NORMALIZE_NEWLINES); | |
| 3583 | - | |
| 3584 | -$td->runtest("xref loop with append", | |
| 3585 | - {$td->COMMAND => | |
| 3586 | - "qpdf --deterministic-id append-xref-loop.pdf a.pdf"}, | |
| 3587 | - {$td->FILE => "append-xref-loop.out", | |
| 3588 | - $td->EXIT_STATUS => 3}, | |
| 3589 | - $td->NORMALIZE_NEWLINES); | |
| 3590 | -$td->runtest("check output", | |
| 3591 | - {$td->FILE => "a.pdf"}, | |
| 3592 | - {$td->FILE => "append-xref-loop-fixed.pdf"}); | |
| 3593 | - | |
| 3594 | -$td->runtest("endobj not at newline", | |
| 3595 | - {$td->COMMAND => | |
| 3596 | - "qpdf --deterministic-id endobj-at-eol.pdf a.pdf"}, | |
| 3597 | - {$td->FILE => "endobj-at-eol.out", | |
| 3598 | - $td->EXIT_STATUS => 3}, | |
| 3599 | - $td->NORMALIZE_NEWLINES); | |
| 3600 | -$td->runtest("check output", | |
| 3601 | - {$td->FILE => "a.pdf"}, | |
| 3602 | - {$td->FILE => "endobj-at-eol-fixed.pdf"}); | |
| 3603 | - | |
| 3604 | -show_ntests(); | |
| 3605 | -# ---------- | |
| 3606 | -$td->notify("--- Basic Parsing Tests ---"); | |
| 3607 | -# $n_tests incremented below after initialization of @goodfiles. | |
| 3608 | - | |
| 3609 | -my @goodfiles = ("implicit null", # 1 | |
| 3610 | - "direct null", # 2 | |
| 3611 | - "unresolved null", # 3 | |
| 3612 | - "indirect null", # 4 | |
| 3613 | - "indirect bool, real", # 5 | |
| 3614 | - "direct bool", # 6 | |
| 3615 | - "integer", # 7 | |
| 3616 | - "real, ASCIIHexDecode", # 8 | |
| 3617 | - "string", # 9 | |
| 3618 | - "array", # 10 | |
| 3619 | - "dictionary", # 11 | |
| 3620 | - "stream", # 12 | |
| 3621 | - "nesting, strings, names", # 13 | |
| 3622 | - "tokenizing pipeline", # 14 | |
| 3623 | - "name", # 15 | |
| 3624 | - "object-stream", # 16 | |
| 3625 | - "hybrid xref", # 17 | |
| 3626 | - "hybrid xref old mode", # 18 | |
| 3627 | - "xref with prev", # 19 | |
| 3628 | - "lots of compressible objects", # 20 | |
| 3629 | - "array with indirect nulls", # 21 | |
| 3630 | - ); | |
| 3631 | - | |
| 3632 | -$n_tests += (3 * @goodfiles) + 6; | |
| 3633 | - | |
| 3634 | -my %goodtest_overrides = ('14' => 3); | |
| 3635 | -my %goodtest_flags = | |
| 3636 | - ('18' => '-ignore-xref-streams', | |
| 3637 | - '20' => '-object-streams=generate', | |
| 3638 | - ); | |
| 3639 | -for (my $i = 1; $i <= scalar(@goodfiles); ++$i) | |
| 3640 | -{ | |
| 3641 | - my $n = $goodtest_overrides{$i} || 1; | |
| 3642 | - $td->runtest("$goodfiles[$i-1]", | |
| 3643 | - {$td->COMMAND => "test_driver $n good$i.pdf"}, | |
| 3644 | - {$td->FILE => "good$i.out", | |
| 3645 | - $td->EXIT_STATUS => 0}, | |
| 3646 | - $td->NORMALIZE_NEWLINES); | |
| 3647 | - my $xflags = $goodtest_flags{$i} || ''; | |
| 3648 | - check_pdf("create qdf", | |
| 3649 | - "qpdf --static-id -qdf $xflags good$i.pdf", | |
| 3650 | - "good$i.qdf", 0); | |
| 3651 | -} | |
| 3652 | - | |
| 3653 | -check_pdf("no normalization", | |
| 3654 | - "qpdf -qdf --static-id --normalize-content=n good7.pdf", | |
| 3655 | - "good7-not-normalized.qdf", | |
| 3656 | - 0); | |
| 3657 | - | |
| 3658 | -check_pdf("no qdf", | |
| 3659 | - "qpdf --static-id good17.pdf", | |
| 3660 | - "good17-not-qdf.pdf", | |
| 3661 | - 0); | |
| 3662 | - | |
| 3663 | -check_pdf("no recompression", | |
| 3664 | - "qpdf --static-id --stream-data=preserve good17.pdf", | |
| 3665 | - "good17-not-recompressed.pdf", | |
| 3666 | - 0); | |
| 3667 | - | |
| 3668 | -show_ntests(); | |
| 3669 | -# ---------- | |
| 3670 | -$td->notify("--- Name Normalization Tests ---"); | |
| 3671 | -$n_tests += 6; | |
| 3672 | - | |
| 3673 | -$td->runtest("check pound in name", | |
| 3674 | - {$td->COMMAND => | |
| 3675 | - "test_driver 1 pound-in-name.pdf"}, | |
| 3676 | - {$td->FILE => "pound-in-name.out", | |
| 3677 | - $td->EXIT_STATUS => 0}, | |
| 3678 | - $td->NORMALIZE_NEWLINES); | |
| 3679 | -$td->runtest("convert pound in name", | |
| 3680 | - {$td->COMMAND => "qpdf --static-id --qdf" . | |
| 3681 | - " pound-in-name.pdf a.pdf"}, | |
| 3682 | - {$td->FILE => "pound-in-name-qdf.out", | |
| 3683 | - $td->EXIT_STATUS => 3}, | |
| 3684 | - $td->NORMALIZE_NEWLINES); | |
| 3685 | -$td->runtest("check output", | |
| 3686 | - {$td->FILE => "a.pdf"}, | |
| 3687 | - {$td->FILE => "pound-in-name.qdf"}); | |
| 3688 | - | |
| 3689 | -$td->runtest("check pound in image names", | |
| 3690 | - {$td->COMMAND => | |
| 3691 | - "qpdf --check name-pound-images.pdf"}, | |
| 3692 | - {$td->FILE => "name-pound-images.out", | |
| 3693 | - $td->EXIT_STATUS => 3}, | |
| 3694 | - $td->NORMALIZE_NEWLINES); | |
| 3695 | -$td->runtest("convert pound in image names", | |
| 3696 | - {$td->COMMAND => "qpdf --static-id --qdf" . | |
| 3697 | - " name-pound-images.pdf a.pdf"}, | |
| 3698 | - {$td->FILE => "name-pound-images-qdf.out", | |
| 3699 | - $td->EXIT_STATUS => 3}, | |
| 3700 | - $td->NORMALIZE_NEWLINES); | |
| 3701 | -$td->runtest("check output", | |
| 3702 | - {$td->FILE => "a.pdf"}, | |
| 3703 | - {$td->FILE => "name-pound-images.qdf"}); | |
| 3704 | - | |
| 3705 | -show_ntests(); | |
| 3706 | -# ---------- | |
| 3707 | -$td->notify("--- C API Tests ---"); | |
| 3708 | - | |
| 3709 | -my @capi = ( | |
| 3710 | - [2, 'no options'], | |
| 3711 | - [3, 'normalized content'], | |
| 3712 | - [4, 'ignore xref streams'], | |
| 3713 | - [5, 'linearized'], | |
| 3714 | - [6, 'object streams'], | |
| 3715 | - [7, 'qdf'], | |
| 3716 | - [8, 'no original object ids'], | |
| 3717 | - [9, 'uncompressed streams'], | |
| 3718 | - ); | |
| 3719 | -$n_tests += (2 * @capi) + 5; | |
| 3720 | -foreach my $d (@capi) | |
| 3721 | -{ | |
| 3722 | - my ($n, $description) = @$d; | |
| 3723 | - my $outfile = $description; | |
| 3724 | - $outfile =~ s/ /-/g; | |
| 3725 | - $outfile = "c-$outfile.pdf"; | |
| 3726 | - $td->runtest($description, | |
| 3727 | - {$td->COMMAND => "qpdf-ctest $n hybrid-xref.pdf '' a.pdf"}, | |
| 3728 | - {$td->STRING => "C test $n done\n", $td->EXIT_STATUS => 0}, | |
| 3729 | - $td->NORMALIZE_NEWLINES); | |
| 3730 | - $td->runtest("check $description", | |
| 3731 | - {$td->FILE => "a.pdf"}, | |
| 3732 | - {$td->FILE => $outfile}); | |
| 3733 | -} | |
| 3734 | -$td->runtest("write to bad file name", | |
| 3735 | - {$td->COMMAND => "qpdf-ctest 2 hybrid-xref.pdf '' /:a:/:b:"}, | |
| 3736 | - {$td->REGEXP => "error: open /:a:/:b:: .*", | |
| 3737 | - $td->EXIT_STATUS => 0}, | |
| 3738 | - $td->NORMALIZE_NEWLINES); | |
| 3739 | - | |
| 3740 | -$td->runtest("write damaged to bad file name", | |
| 3741 | - {$td->COMMAND => "qpdf-ctest 2 append-page-content-damaged.pdf" . | |
| 3742 | - " '' /:a:/:b:"}, | |
| 3743 | - {$td->REGEXP => | |
| 3744 | - "warning:(?s:.*)\n" . | |
| 3745 | - "error: open /:a:/:b:: .*", | |
| 3746 | - $td->EXIT_STATUS => 0}, | |
| 3747 | - $td->NORMALIZE_NEWLINES); | |
| 3748 | - | |
| 3749 | -$td->runtest("write damaged", | |
| 3750 | - {$td->COMMAND => "qpdf-ctest 2 append-page-content-damaged.pdf" . | |
| 3751 | - " '' a.pdf"}, | |
| 3752 | - {$td->FILE => "c-write-damaged.out", | |
| 3753 | - $td->EXIT_STATUS => 0}, | |
| 3754 | - $td->NORMALIZE_NEWLINES); | |
| 3755 | - | |
| 3756 | -$td->runtest("empty PDF", | |
| 3757 | - {$td->COMMAND => "qpdf-ctest 41 - '' a.pdf"}, | |
| 3758 | - {$td->STRING => "C test 41 done\n", $td->EXIT_STATUS => 0}, | |
| 3759 | - $td->NORMALIZE_NEWLINES); | |
| 3760 | -$td->runtest("check output", | |
| 3761 | - {$td->FILE => "a.pdf"}, | |
| 3762 | - {$td->FILE => "c-empty.pdf"}); | |
| 3763 | - | |
| 3764 | -show_ntests(); | |
| 3765 | -# ---------- | |
| 3766 | -$td->notify("--- Deterministic ID Tests ---"); | |
| 3767 | -$n_tests += 11; | |
| 3768 | -foreach my $d ('nn', 'ny', 'yn', 'yy') | |
| 3769 | -{ | |
| 3770 | - my $linearize = ($d =~ m/^y/); | |
| 3771 | - my $ostream = ($d =~ m/y$/); | |
| 3772 | - $td->runtest("deterministic ID: linearize/ostream=$d", | |
| 3773 | - {$td->COMMAND => | |
| 3774 | - "qpdf -deterministic-id" . | |
| 3775 | - ($linearize ? " -linearize" : "") . | |
| 3776 | - " -object-streams=" . ($ostream ? "generate" : "disable") . | |
| 3777 | - " deterministic-id-in.pdf a.pdf"}, | |
| 3778 | - {$td->STRING => "", | |
| 3779 | - $td->EXIT_STATUS => 0}); | |
| 3780 | - $td->runtest("compare files", | |
| 3781 | - {$td->FILE => "a.pdf"}, | |
| 3782 | - {$td->FILE => "deterministic-id-$d.pdf"}); | |
| 3783 | -} | |
| 3784 | - | |
| 3785 | -$td->runtest("deterministic ID with encryption", | |
| 3786 | - {$td->COMMAND => "qpdf -deterministic-id encrypted-with-images.pdf a.pdf"}, | |
| 3787 | - {$td->STRING => "qpdf: INTERNAL ERROR: QPDFWriter::generateID" . | |
| 3788 | - " has no data for deterministic ID." . | |
| 3789 | - " This may happen if deterministic ID and" . | |
| 3790 | - " file encryption are requested together.\n", | |
| 3791 | - $td->EXIT_STATUS => 2}, | |
| 3792 | - $td->NORMALIZE_NEWLINES); | |
| 3793 | -$td->runtest("deterministic ID (C API)", | |
| 3794 | - {$td->COMMAND => | |
| 3795 | - "qpdf-ctest 19 deterministic-id-in.pdf '' a.pdf"}, | |
| 3796 | - {$td->STRING => "C test 19 done\n", | |
| 3797 | - $td->EXIT_STATUS => 0}, | |
| 3798 | - $td->NORMALIZE_NEWLINES); | |
| 3799 | -$td->runtest("compare files", | |
| 3800 | - {$td->FILE => "a.pdf"}, | |
| 3801 | - {$td->FILE => "deterministic-id-nn.pdf"}); | |
| 3802 | - | |
| 3803 | -# ---------- | |
| 3804 | -$td->notify("--- Object Stream Tests ---"); | |
| 3805 | -$n_tests += (36 * 4) + (12 * 2); | |
| 3806 | -$n_compare_pdfs += 36; | |
| 3807 | - | |
| 3808 | -for (my $n = 16; $n <= 19; ++$n) | |
| 3809 | -{ | |
| 3810 | - my $in = "good$n.pdf"; | |
| 3811 | - foreach my $flags ('-object-streams=disable', | |
| 3812 | - '-object-streams=preserve', | |
| 3813 | - '-object-streams=generate') | |
| 3814 | - { | |
| 3815 | - foreach my $qdf ('-qdf', '', '-allow-weak-crypto -encrypt "" x 128 --') | |
| 3816 | - { | |
| 3817 | - # 4 tests + 1 compare_pdfs * 36 cases | |
| 3818 | - # 2 additional tests * 12 cases | |
| 3819 | - $td->runtest("object stream mode", | |
| 3820 | - {$td->COMMAND => | |
| 3821 | - "qpdf --static-id $flags $qdf $in a.pdf"}, | |
| 3822 | - {$td->STRING => "", | |
| 3823 | - $td->EXIT_STATUS => 0}); | |
| 3824 | - compare_pdfs("good$n.pdf", "a.pdf"); | |
| 3825 | - if ($qdf eq '-qdf') | |
| 3826 | - { | |
| 3827 | - $td->runtest("fix-qdf identity check", | |
| 3828 | - {$td->COMMAND => "fix-qdf a.pdf >| b.pdf"}, | |
| 3829 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3830 | - $td->runtest("compare files", | |
| 3831 | - {$td->FILE => "a.pdf"}, | |
| 3832 | - {$td->FILE => "b.pdf"}); | |
| 3833 | - } | |
| 3834 | - $td->runtest("convert to qdf", | |
| 3835 | - {$td->COMMAND => | |
| 3836 | - "qpdf --static-id --no-original-object-ids" . | |
| 3837 | - " -qdf -decrypt" . | |
| 3838 | - " -object-streams=disable $in a.qdf"}, | |
| 3839 | - {$td->STRING => "", | |
| 3840 | - $td->EXIT_STATUS => 0}); | |
| 3841 | - $td->runtest("convert output to qdf", | |
| 3842 | - {$td->COMMAND => | |
| 3843 | - "qpdf --static-id --no-original-object-ids" . | |
| 3844 | - " -qdf -object-streams=disable a.pdf b.qdf"}, | |
| 3845 | - {$td->STRING => "", | |
| 3846 | - $td->EXIT_STATUS => 0}); | |
| 3847 | - $td->runtest("compare files", | |
| 3848 | - {$td->FILE => "a.qdf"}, | |
| 3849 | - {$td->FILE => "b.qdf"}); | |
| 3850 | - } | |
| 3851 | - } | |
| 3852 | - flush_tiff_cache(); | |
| 3853 | -} | |
| 3854 | - | |
| 3855 | -show_ntests(); | |
| 3856 | -# ---------- | |
| 3857 | -$td->notify("--- Specific File Tests ---"); | |
| 3858 | -$n_tests += 11; | |
| 3859 | - | |
| 3860 | -# Special PDF files that caused problems at some point | |
| 3861 | - | |
| 3862 | -$td->runtest("damaged stream", | |
| 3863 | - {$td->COMMAND => "qpdf --check damaged-stream.pdf"}, | |
| 3864 | - {$td->FILE => "damaged-stream.out", $td->EXIT_STATUS => 3}, | |
| 3865 | - $td->NORMALIZE_NEWLINES); | |
| 3866 | -$td->runtest("damaged stream (C)", | |
| 3867 | - {$td->COMMAND => "qpdf-ctest 2 damaged-stream.pdf '' a.pdf"}, | |
| 3868 | - {$td->FILE => "damaged-stream-c-check.out", $td->EXIT_STATUS => 0}, | |
| 3869 | - $td->NORMALIZE_NEWLINES); | |
| 3870 | -$td->runtest("compress objstm and xref", | |
| 3871 | - {$td->COMMAND => | |
| 3872 | - "qpdf --static-id --stream-data=compress". | |
| 3873 | - " --object-streams=generate minimal.pdf a.pdf"}, | |
| 3874 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 3875 | - $td->NORMALIZE_NEWLINES); | |
| 3876 | -$td->runtest("check output", | |
| 3877 | - {$td->FILE => "a.pdf"}, | |
| 3878 | - {$td->FILE => "compress-objstm-xref.pdf"}); | |
| 3879 | -$td->runtest("qdf + preserved-unreferenced + xref streams", | |
| 3880 | - {$td->COMMAND => "qpdf --qdf --preserve-unreferenced" . | |
| 3881 | - " --static-id compress-objstm-xref.pdf a.pdf"}, | |
| 3882 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 3883 | -$td->runtest("check output", | |
| 3884 | - {$td->FILE => "a.pdf"}, | |
| 3885 | - {$td->FILE => "compress-objstm-xref-qdf.pdf"}); | |
| 3886 | -$td->runtest("check fix-qdf idempotency", | |
| 3887 | - {$td->COMMAND => "fix-qdf a.pdf"}, | |
| 3888 | - {$td->FILE => "a.pdf", $td->EXIT_STATUS => 0}); | |
| 3889 | -$td->runtest("pages points to page", | |
| 3890 | - {$td->COMMAND => | |
| 3891 | - "qpdf --static-id --linearize pages-is-page.pdf a.pdf"}, | |
| 3892 | - {$td->FILE => "pages-is-page.out", $td->EXIT_STATUS => 3}, | |
| 3893 | - $td->NORMALIZE_NEWLINES); | |
| 3894 | -$td->runtest("check output", | |
| 3895 | - {$td->FILE => "a.pdf"}, | |
| 3896 | - {$td->FILE => "pages-is-page-out.pdf"}); | |
| 3897 | -$td->runtest("Acroform /DR with indirect subkey", | |
| 3898 | - {$td->COMMAND => | |
| 3899 | - "qpdf --static-id --empty" . | |
| 3900 | - " --pages dr-with-indirect-item.pdf -- a.pdf"}, | |
| 3901 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 3902 | - $td->NORMALIZE_NEWLINES); | |
| 3903 | -$td->runtest("check output", | |
| 3904 | - {$td->FILE => "a.pdf"}, | |
| 3905 | - {$td->FILE => "dr-with-indirect-item-out.pdf"}); | |
| 3906 | - | |
| 3907 | -show_ntests(); | |
| 3908 | -# ---------- | |
| 3909 | -$td->notify("--- Mutability Tests ---"); | |
| 3910 | -$n_tests += 5; | |
| 3911 | - | |
| 3912 | -$td->runtest("no normalization", | |
| 3913 | - {$td->COMMAND => "test_driver 4 test4-1.pdf"}, | |
| 3914 | - {$td->FILE => "test4-1.qdf", | |
| 3915 | - $td->EXIT_STATUS => 0}); | |
| 3916 | - | |
| 3917 | -$td->runtest("object ordering", | |
| 3918 | - {$td->COMMAND => "test_driver 4 test4-4.pdf"}, | |
| 3919 | - {$td->FILE => "test4-4.qdf", | |
| 3920 | - $td->EXIT_STATUS => 0}); | |
| 3921 | - | |
| 3922 | -$td->runtest("make direct with allow_streams", | |
| 3923 | - {$td->COMMAND => "test_driver 4 test4-5.pdf"}, | |
| 3924 | - {$td->FILE => "test4-5.qdf", | |
| 3925 | - $td->EXIT_STATUS => 0}); | |
| 3926 | - | |
| 3927 | -$td->runtest("stream detected", | |
| 3928 | - {$td->COMMAND => "test_driver 4 test4-2.pdf"}, | |
| 3929 | - {$td->FILE => "test4-2.out", | |
| 3930 | - $td->EXIT_STATUS => 2}, | |
| 3931 | - $td->NORMALIZE_NEWLINES); | |
| 3932 | - | |
| 3933 | -$td->runtest("loop detected", | |
| 3934 | - {$td->COMMAND => "test_driver 4 test4-3.pdf"}, | |
| 3935 | - {$td->FILE => "test4-3.out", | |
| 3936 | - $td->EXIT_STATUS => 2}, | |
| 3937 | - $td->NORMALIZE_NEWLINES); | |
| 3938 | - | |
| 3939 | -show_ntests(); | |
| 3940 | -# ---------- | |
| 3941 | -$td->notify("--- Extraction Tests ---"); | |
| 3942 | -$n_tests += 13; | |
| 3943 | - | |
| 3944 | -$td->runtest("show xref", | |
| 3945 | - {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 3946 | - " --show-xref"}, | |
| 3947 | - {$td->FILE => "show-xref.out", | |
| 3948 | - $td->EXIT_STATUS => 0}, | |
| 3949 | - $td->NORMALIZE_NEWLINES); | |
| 3950 | - | |
| 3951 | -$td->runtest("show pages", | |
| 3952 | - {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 3953 | - " --show-pages"}, | |
| 3954 | - {$td->FILE => "show-pages.out", | |
| 3955 | - $td->EXIT_STATUS => 0}, | |
| 3956 | - $td->NORMALIZE_NEWLINES); | |
| 3957 | - | |
| 3958 | -$td->runtest("show-pages-images", | |
| 3959 | - {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 3960 | - " --show-pages --with-images"}, | |
| 3961 | - {$td->FILE => "show-pages-images.out", | |
| 3962 | - $td->EXIT_STATUS => 0}, | |
| 3963 | - $td->NORMALIZE_NEWLINES); | |
| 3964 | - | |
| 3965 | -$td->runtest("show-pages-images", | |
| 3966 | - {$td->COMMAND => "qpdf shared-images.pdf" . | |
| 3967 | - " --show-pages --with-images"}, | |
| 3968 | - {$td->FILE => "shared-images-show.out", | |
| 3969 | - $td->EXIT_STATUS => 0}, | |
| 3970 | - $td->NORMALIZE_NEWLINES); | |
| 3971 | - | |
| 3972 | -$td->runtest("show-page-1", | |
| 3973 | - {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 3974 | - " --show-object=5,0"}, | |
| 3975 | - {$td->FILE => "show-page-1.out", | |
| 3976 | - $td->EXIT_STATUS => 0}, | |
| 3977 | - $td->NORMALIZE_NEWLINES); | |
| 3978 | - | |
| 3979 | -$td->runtest("show-page-1-content-raw", | |
| 3980 | - {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 3981 | - " --show-object=7 --raw-stream-data"}, | |
| 3982 | - {$td->FILE => "show-page-1-content-raw.out", | |
| 3983 | - $td->EXIT_STATUS => 0}); | |
| 3984 | - | |
| 3985 | -$td->runtest("show-page-1-content-filtered", | |
| 3986 | - {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 3987 | - " --show-object=7 --filtered-stream-data"}, | |
| 3988 | - {$td->FILE => "show-page-1-content-filtered.out", | |
| 3989 | - $td->EXIT_STATUS => 0}); | |
| 3990 | - | |
| 3991 | -$td->runtest("show-page-1-content-normalized", | |
| 3992 | - {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 3993 | - " --show-object=7,0 --filtered-stream-data --normalize-content=y"}, | |
| 3994 | - {$td->FILE => "show-page-1-content-normalized.out", | |
| 3995 | - $td->EXIT_STATUS => 0}); | |
| 3996 | - | |
| 3997 | -$td->runtest("show-page-1-image", | |
| 3998 | - {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 3999 | - " --show-object=8 --raw-stream-data"}, | |
| 4000 | - {$td->FILE => "show-page-1-image.out", | |
| 4001 | - $td->EXIT_STATUS => 0}); | |
| 4002 | - | |
| 4003 | -$td->runtest("unfilterable stream data", | |
| 4004 | - {$td->COMMAND => "qpdf unfilterable.pdf" . | |
| 4005 | - " --show-object=4 --filtered-stream-data"}, | |
| 4006 | - {$td->FILE => "show-unfilterable.out", | |
| 4007 | - $td->EXIT_STATUS => 2}, | |
| 4008 | - $td->NORMALIZE_NEWLINES); | |
| 4009 | - | |
| 4010 | -$td->runtest("show-xref-by-id", | |
| 4011 | - {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 4012 | - " --show-object=12"}, | |
| 4013 | - {$td->FILE => "show-xref-by-id.out", | |
| 4014 | - $td->EXIT_STATUS => 0}, | |
| 4015 | - $td->NORMALIZE_NEWLINES); | |
| 4016 | - | |
| 4017 | -$td->runtest("show-xref-by-id-filtered", | |
| 4018 | - {$td->COMMAND => "qpdf encrypted-with-images.pdf" . | |
| 4019 | - " --show-object=12 --filtered-stream-data"}, | |
| 4020 | - {$td->FILE => "show-xref-by-id-filtered.out", | |
| 4021 | - $td->EXIT_STATUS => 0}); | |
| 4022 | - | |
| 4023 | -$td->runtest("show trailer", | |
| 4024 | - {$td->COMMAND => "qpdf minimal.pdf --show-object=trailer"}, | |
| 4025 | - {$td->FILE => "show-trailer.out", | |
| 4026 | - $td->EXIT_STATUS => 0}, | |
| 4027 | - $td->NORMALIZE_NEWLINES); | |
| 4028 | - | |
| 4029 | -show_ntests(); | |
| 4030 | -# ---------- | |
| 4031 | -$td->notify("--- Clear-text Metadata Tests ---"); | |
| 4032 | -$n_tests += 58; | |
| 4033 | - | |
| 4034 | -# args: file, exp_encrypted, exp_cleartext | |
| 4035 | -check_metadata("compressed-metadata.pdf", 0, 0); | |
| 4036 | -check_metadata("enc-base.pdf", 0, 1); | |
| 4037 | - | |
| 4038 | -foreach my $f (qw(compressed-metadata.pdf enc-base.pdf)) | |
| 4039 | -{ | |
| 4040 | - foreach my $w (qw(compress preserve)) | |
| 4041 | - { | |
| 4042 | - $td->runtest("$w streams ($f)", | |
| 4043 | - {$td->COMMAND => "qpdf --stream-data=$w $f a.pdf"}, | |
| 4044 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4045 | - check_metadata("a.pdf", 0, 1); | |
| 4046 | - $td->runtest("encrypt normally", | |
| 4047 | - {$td->COMMAND => | |
| 4048 | - "qpdf --allow-weak-crypto" . | |
| 4049 | - " --encrypt '' o 128 -- a.pdf b.pdf"}, | |
| 4050 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4051 | - check_metadata("b.pdf", 1, 0); | |
| 4052 | - unlink "b.pdf"; | |
| 4053 | - $td->runtest("encrypt V4", | |
| 4054 | - {$td->COMMAND => | |
| 4055 | - "qpdf --allow-weak-crypto" . | |
| 4056 | - " --encrypt '' o 128 --force-V4 -- a.pdf b.pdf"}, | |
| 4057 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4058 | - check_metadata("b.pdf", 1, 0); | |
| 4059 | - unlink "b.pdf"; | |
| 4060 | - $td->runtest("encrypt with cleartext metadata", | |
| 4061 | - {$td->COMMAND => | |
| 4062 | - "qpdf --allow-weak-crypto" . | |
| 4063 | - " --encrypt '' o 128 --cleartext-metadata --" . | |
| 4064 | - " a.pdf b.pdf"}, | |
| 4065 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4066 | - check_metadata("b.pdf", 1, 1); | |
| 4067 | - $td->runtest("preserve encryption", | |
| 4068 | - {$td->COMMAND => "qpdf b.pdf c.pdf"}, | |
| 4069 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4070 | - check_metadata("c.pdf", 1, 1); | |
| 4071 | - unlink "b.pdf", "c.pdf"; | |
| 4072 | - $td->runtest("encrypt with aes and cleartext metadata", | |
| 4073 | - {$td->COMMAND => | |
| 4074 | - "qpdf --encrypt '' o 128" . | |
| 4075 | - " --cleartext-metadata --use-aes=y -- a.pdf b.pdf"}, | |
| 4076 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4077 | - check_metadata("b.pdf", 1, 1); | |
| 4078 | - $td->runtest("preserve encryption", | |
| 4079 | - {$td->COMMAND => "qpdf b.pdf c.pdf"}, | |
| 4080 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4081 | - check_metadata("c.pdf", 1, 1); | |
| 4082 | - unlink "b.pdf", "c.pdf"; | |
| 4083 | - } | |
| 4084 | -} | |
| 4085 | - | |
| 4086 | -show_ntests(); | |
| 4087 | -# ---------- | |
| 4088 | -$td->notify("--- Weak Cryptography ---"); | |
| 4089 | -$n_tests += 4; | |
| 4090 | -$td->runtest("256-bit: no warning", | |
| 4091 | - {$td->COMMAND => 'qpdf --encrypt "" "" 256 -- minimal.pdf a.pdf'}, | |
| 4092 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 4093 | - $td->NORMALIZE_NEWLINES); | |
| 4094 | -$td->runtest("128-bit with AES: no warning", | |
| 4095 | - {$td->COMMAND => 'qpdf --encrypt "" "" 128 --use-aes=y --' . | |
| 4096 | - ' minimal.pdf a.pdf'}, | |
| 4097 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 4098 | - $td->NORMALIZE_NEWLINES); | |
| 4099 | -$td->runtest("128-bit without AES: error", | |
| 4100 | - {$td->COMMAND => 'qpdf --encrypt "" "" 128 -- minimal.pdf a.pdf'}, | |
| 4101 | - {$td->REGEXP => "Pass --allow-weak-crypto to enable", | |
| 4102 | - $td->EXIT_STATUS => 2}, | |
| 4103 | - $td->NORMALIZE_NEWLINES); | |
| 4104 | -$td->runtest("40-bit: error", | |
| 4105 | - {$td->COMMAND => 'qpdf --encrypt "" "" 40 -- minimal.pdf a.pdf'}, | |
| 4106 | - {$td->REGEXP => "Pass --allow-weak-crypto to enable", | |
| 4107 | - $td->EXIT_STATUS => 2}, | |
| 4108 | - $td->NORMALIZE_NEWLINES); | |
| 4109 | - | |
| 4110 | -show_ntests(); | |
| 4111 | -# ---------- | |
| 4112 | -$td->notify("--- Linearization Tests ---"); | |
| 4113 | -# $n_tests incremented after initialization of @linearized_files and | |
| 4114 | -# @to_linearize. | |
| 4115 | - | |
| 4116 | -# *'ed files were linearized with Pdlin. | |
| 4117 | -my @linearized_files = | |
| 4118 | - ('lin0', # not linearized | |
| 4119 | - 'lin1', # * outlines, page labels, pdlin | |
| 4120 | - 'lin2', # * lin1 with null and newline | |
| 4121 | - 'lin3', # same file saved with acrobat | |
| 4122 | - 'lin4', # * lin1 with no /PageMode | |
| 4123 | - 'lin5', # lin3 with embedded thumbnails | |
| 4124 | - 'lin6', # * lin5 with pdlin | |
| 4125 | - 'lin7', # lin5 with /PageMode /UseThumbs | |
| 4126 | - 'lin8', # * lin7 with pdlin | |
| 4127 | - 'lin9', # * shared objects, indirect null | |
| 4128 | - 'badlin1', # parameter dictionary errors | |
| 4129 | - ); | |
| 4130 | - | |
| 4131 | -my @to_linearize = | |
| 4132 | - ('lin-special', # lots of weird cases -- see file comments | |
| 4133 | - 'delete-and-reuse', # deleted, reused objects | |
| 4134 | - 'lin-delete-and-reuse', # linearized, then delete and reuse | |
| 4135 | - 'object-stream', # contains object streams | |
| 4136 | - 'hybrid-xref', # contains both xref tables and streams | |
| 4137 | - 'gen1', # has objects with generation > 0 | |
| 4138 | - 'direct-outlines', # /Outlines is a direct object | |
| 4139 | - @linearized_files, # we should be able to relinearize | |
| 4140 | - ); | |
| 4141 | - | |
| 4142 | -$n_tests += @linearized_files + 6; | |
| 4143 | -$n_tests += (3 * @to_linearize * 5) + 6; | |
| 4144 | - | |
| 4145 | -foreach my $base (@linearized_files) | |
| 4146 | -{ | |
| 4147 | - $td->runtest("dump linearization: $base", | |
| 4148 | - {$td->COMMAND => "qpdf --show-linearization $base.pdf"}, | |
| 4149 | - {$td->FILE => "$base.out", | |
| 4150 | - $td->EXIT_STATUS => 0}, | |
| 4151 | - $td->NORMALIZE_NEWLINES); | |
| 4152 | -} | |
| 4153 | - | |
| 4154 | -# Check normal modified and linearized modified files, making sure | |
| 4155 | -# that their qdf files are identical. The next two tests have the | |
| 4156 | -# same expected output files and different input files. | |
| 4157 | -check_pdf("modified", | |
| 4158 | - "qpdf --static-id --qdf --no-original-object-ids" . | |
| 4159 | - " delete-and-reuse.pdf", "delete-and-reuse.qdf", | |
| 4160 | - 0); | |
| 4161 | -check_pdf("linearized and modified", | |
| 4162 | - "qpdf --static-id --qdf --no-original-object-ids" . | |
| 4163 | - " lin-delete-and-reuse.pdf", "delete-and-reuse.qdf", # same output | |
| 4164 | - 0); | |
| 4165 | - | |
| 4166 | -$td->runtest("check linearized and modified", | |
| 4167 | - {$td->COMMAND => "qpdf --check lin-delete-and-reuse.pdf"}, | |
| 4168 | - {$td->FILE => "lin-delete-and-reuse-check.out", | |
| 4169 | - $td->EXIT_STATUS => 0}, | |
| 4170 | - $td->NORMALIZE_NEWLINES); | |
| 4171 | -$td->runtest("check multiple modifications", | |
| 4172 | - {$td->COMMAND => "qpdf --check delete-and-reuse.pdf"}, | |
| 4173 | - {$td->FILE => "delete-and-reuse-check.out", | |
| 4174 | - $td->EXIT_STATUS => 0}, | |
| 4175 | - $td->NORMALIZE_NEWLINES); | |
| 4176 | - | |
| 4177 | -foreach my $base (@to_linearize) | |
| 4178 | -{ | |
| 4179 | - foreach my $omode (qw(disable preserve generate)) | |
| 4180 | - { | |
| 4181 | - my $oarg = "-object-streams=$omode"; | |
| 4182 | - my $sdarg = ""; | |
| 4183 | - if (($base eq 'lin-special') || ($base eq 'object-stream')) | |
| 4184 | - { | |
| 4185 | - $sdarg = "--stream-data=uncompress"; | |
| 4186 | - } | |
| 4187 | - $td->runtest("linearize $base ($omode)", | |
| 4188 | - {$td->COMMAND => | |
| 4189 | - "qpdf -linearize $oarg $sdarg" . | |
| 4190 | - " --static-id $base.pdf a.pdf"}, | |
| 4191 | - {$td->STRING => "", | |
| 4192 | - $td->EXIT_STATUS => 0}); | |
| 4193 | - $td->runtest("check linearization", | |
| 4194 | - {$td->COMMAND => "qpdf --check-linearization a.pdf"}, | |
| 4195 | - {$td->STRING => "a.pdf: no linearization errors\n", | |
| 4196 | - $td->EXIT_STATUS => 0}, | |
| 4197 | - $td->NORMALIZE_NEWLINES); | |
| 4198 | - # Relinearizing twice should produce identical results. We | |
| 4199 | - # have to do it twice because, if objects changed ordering | |
| 4200 | - # during the original linearization, the hint tables won't | |
| 4201 | - # exactly match. This is because object identifiers are | |
| 4202 | - # inserted into the hint table in their original order since | |
| 4203 | - # we don't yet have renumbering information when we compute | |
| 4204 | - # the table values. | |
| 4205 | - $td->runtest("relinearize $base 1", | |
| 4206 | - {$td->COMMAND => | |
| 4207 | - "qpdf -linearize $sdarg --static-id a.pdf b.pdf"}, | |
| 4208 | - {$td->STRING => "", | |
| 4209 | - $td->EXIT_STATUS => 0}); | |
| 4210 | - $td->runtest("relinearize $base 2", | |
| 4211 | - {$td->COMMAND => | |
| 4212 | - "qpdf -linearize $sdarg --static-id b.pdf c.pdf"}, | |
| 4213 | - {$td->STRING => "", | |
| 4214 | - $td->EXIT_STATUS => 0}); | |
| 4215 | - $td->runtest("compare files ($omode)", | |
| 4216 | - {$td->FILE => "b.pdf"}, | |
| 4217 | - {$td->FILE => "c.pdf"}); | |
| 4218 | - if (($base eq 'lin-special') || ($base eq 'object-stream')) | |
| 4219 | - { | |
| 4220 | - $td->runtest("check $base ($omode)", | |
| 4221 | - {$td->FILE => "a.pdf"}, | |
| 4222 | - {$td->FILE => "$base.$omode.exp"}); | |
| 4223 | - } | |
| 4224 | - } | |
| 4225 | -} | |
| 4226 | - | |
| 4227 | -show_ntests(); | |
| 4228 | -# ---------- | |
| 4229 | -$td->notify("--- Encryption Tests ---"); | |
| 4230 | -# $n_tests incremented below | |
| 4231 | - | |
| 4232 | -# The enc-file.pdf files were encrypted using Acrobat 5.0, not the | |
| 4233 | -# qpdf library. The files are decrypted using qpdf, then re-encrypted | |
| 4234 | -# using qpdf with specific flags. The /P value is checked. The | |
| 4235 | -# resulting files were saved and manually checked with Acrobat 5.0 to | |
| 4236 | -# ensure that the security settings were as intended. | |
| 4237 | - | |
| 4238 | -# The enc-XI-file.pdf files were treated the same way but with Acrobat | |
| 4239 | -# XI instead of Acrobat 5.0. They were used to create test files with | |
| 4240 | -# newer encryption formats. | |
| 4241 | - | |
| 4242 | -# Values: basename, password, encryption flags, /P Encrypt key, | |
| 4243 | -# extract-for-accessibility, extract-for-any-purpose, | |
| 4244 | -# print-low-res, print-high-res, modify-assembly, modify-forms, | |
| 4245 | -# modify-annotate, modify-other, modify-all | |
| 4246 | -my @encrypted_files = | |
| 4247 | - (['base', ''], # 1 | |
| 4248 | - ['R3,V2', '', # 2 | |
| 4249 | - '-accessibility=n -extract=n -print=full -modify=all', -532, | |
| 4250 | - 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1], | |
| 4251 | - ['R3,V2,U=view,O=view', 'view', # 3 | |
| 4252 | - '-accessibility=y -extract=n -print=none -modify=none', -3392, | |
| 4253 | - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], | |
| 4254 | - ['R3,V2,O=master', 'master', # 4 | |
| 4255 | - '-accessibility=n -extract=y -print=none -modify=annotate', -2576, | |
| 4256 | - 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0], | |
| 4257 | - ['R3,V2,O=master', '', # 5 | |
| 4258 | - '-accessibility=n -extract=n -print=none -modify=form', -2624, | |
| 4259 | - 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0], | |
| 4260 | - ['R3,V2,U=view,O=master', 'view', # 6 | |
| 4261 | - '-accessibility=n -extract=n -print=none -modify=assembly', -2880, | |
| 4262 | - 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0], | |
| 4263 | - ['R3,V2,U=view,O=master', 'master', # 7 | |
| 4264 | - '-accessibility=n -print=low', -2564, | |
| 4265 | - 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1], | |
| 4266 | - ['R3,V2,U=view,O=master', 'master', # 8 | |
| 4267 | - '-modify=all -assemble=n', -1028, | |
| 4268 | - 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0], | |
| 4269 | - ['R3,V2,U=view,O=master', 'master', # 9 | |
| 4270 | - '-modify=none -form=y', -1068, | |
| 4271 | - 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0], | |
| 4272 | - ['R3,V2,U=view,O=master', 'master', # 10 | |
| 4273 | - '-modify=annotate -assemble=n', -1036, | |
| 4274 | - 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0], | |
| 4275 | - ['R3,V2,U=view,O=master', 'master', # 11 | |
| 4276 | - '-form=n', -260, | |
| 4277 | - 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0], | |
| 4278 | - ['R3,V2,U=view,O=master', 'master', # 12 | |
| 4279 | - '-annotate=n', -36, | |
| 4280 | - 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0], | |
| 4281 | - ['R3,V2,U=view,O=master', 'master', # 13 | |
| 4282 | - '-modify-other=n', -12, | |
| 4283 | - 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], | |
| 4284 | - ['R2,V1', '', # 14 | |
| 4285 | - '-print=n -modify=n -extract=n -annotate=n', -64, | |
| 4286 | - 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
| 4287 | - ['R2,V1,U=view,O=view', 'view', # 15 | |
| 4288 | - '-print=y -modify=n -extract=n -annotate=n', -60, | |
| 4289 | - 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0], | |
| 4290 | - ['R2,V1,O=master', 'master', # 16 | |
| 4291 | - '-print=n -modify=y -extract=n -annotate=n', -56, | |
| 4292 | - 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0], | |
| 4293 | - ['R2,V1,O=master', '', # 17 | |
| 4294 | - '-print=n -modify=n -extract=y -annotate=n', -48, | |
| 4295 | - 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], | |
| 4296 | - ['R2,V1,U=view,O=master', 'view', # 18 | |
| 4297 | - '-print=n -modify=n -extract=n -annotate=y', -32, | |
| 4298 | - 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], | |
| 4299 | - ['R2,V1,U=view,O=master', 'master', # 19 | |
| 4300 | - '', -4, | |
| 4301 | - 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], | |
| 4302 | - ['long-password', 'asdf asdf asdf asdf asdf asdf qwer'], # 20 | |
| 4303 | - ['long-password', 'asdf asdf asdf asdf asdf asdf qw'], # 21 | |
| 4304 | - ['XI-base', ''], # 22 | |
| 4305 | - ['XI-R6,V5,O=master', '', # 23 | |
| 4306 | - '-extract=n -print=none -modify=assembly', -2368, | |
| 4307 | - 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], | |
| 4308 | - ['XI-R6,V5,O=master', 'master', # 24 | |
| 4309 | - '-extract=n -print=none -modify=assembly', -2368, | |
| 4310 | - 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], | |
| 4311 | - ['XI-R6,V5,U=view,O=master', 'view', # 25 | |
| 4312 | - '-print=low', -2052, | |
| 4313 | - 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1], | |
| 4314 | - ['XI-R6,V5,U=view,O=master', 'master', # 26 | |
| 4315 | - '-print=low', -2052, | |
| 4316 | - 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1], | |
| 4317 | - ['XI-R6,V5,U=view,O=master', 'master', # 27 | |
| 4318 | - '-accessibility=n', -4, # -accessibility=n has no effect | |
| 4319 | - 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], | |
| 4320 | - ['XI-long-password', 'qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm'], # 28; -accessibility=n has no effect | |
| 4321 | - ['XI-long-password', 'qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcv'], # 29 | |
| 4322 | - ['XI-R6,V5,U=wwwww,O=wwwww', 'wwwww', # 30 | |
| 4323 | - '', -4, | |
| 4324 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], | |
| 4325 | - ); | |
| 4326 | - | |
| 4327 | -$n_tests += 8 + (2 * (@encrypted_files)) + (7 * (@encrypted_files - 6)) + 9; | |
| 4328 | - | |
| 4329 | -$td->runtest("encrypted file", | |
| 4330 | - {$td->COMMAND => "test_driver 2 encrypted-with-images.pdf"}, | |
| 4331 | - {$td->FILE => "encrypted1.out", | |
| 4332 | - $td->EXIT_STATUS => 0}, | |
| 4333 | - $td->NORMALIZE_NEWLINES); | |
| 4334 | -$td->runtest("preserve encryption", | |
| 4335 | - {$td->COMMAND => "qpdf encrypted-with-images.pdf encrypted-with-images.enc"}, | |
| 4336 | - {$td->STRING => "", | |
| 4337 | - $td->EXIT_STATUS => 0}); | |
| 4338 | -$td->runtest("recheck encrypted file", | |
| 4339 | - {$td->COMMAND => "test_driver 2 encrypted-with-images.enc"}, | |
| 4340 | - {$td->FILE => "encrypted1.out", | |
| 4341 | - $td->EXIT_STATUS => 0}, | |
| 4342 | - $td->NORMALIZE_NEWLINES); | |
| 4343 | - | |
| 4344 | -$td->runtest("empty owner password", | |
| 4345 | - {$td->COMMAND => "qpdf --encrypt u '' 256 -- minimal.pdf a.pdf"}, | |
| 4346 | - {$td->REGEXP => ".*is insecure.*--allow-insecure.*", | |
| 4347 | - $td->EXIT_STATUS => 2}, | |
| 4348 | - $td->NORMALIZE_NEWLINES); | |
| 4349 | -$td->runtest("allow insecure", | |
| 4350 | - {$td->COMMAND => "qpdf --encrypt u '' 256 --allow-insecure --" . | |
| 4351 | - " minimal.pdf a.pdf"}, | |
| 4352 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 4353 | - $td->NORMALIZE_NEWLINES); | |
| 4354 | -$td->runtest("check insecure", | |
| 4355 | - {$td->COMMAND => "qpdf --check a.pdf"}, | |
| 4356 | - {$td->FILE => "insecure-passwords.out", $td->EXIT_STATUS => 0}, | |
| 4357 | - $td->NORMALIZE_NEWLINES); | |
| 4358 | - | |
| 4359 | -# Test that long passwords that are one character too short fail. We | |
| 4360 | -# test the truncation cases in the loop below by using passwords | |
| 4361 | -# longer than the supported length. | |
| 4362 | -$td->runtest("significant password characters (V < 5)", | |
| 4363 | - {$td->COMMAND => "qpdf --check enc-long-password.pdf" . | |
| 4364 | - " --password='asdf asdf asdf asdf asdf asdf q'"}, | |
| 4365 | - {$td->REGEXP => ".*invalid password.*", $td->EXIT_STATUS => 2}); | |
| 4366 | -$td->runtest("significant password characters (V = 5)", | |
| 4367 | - {$td->COMMAND => "qpdf --check enc-XI-long-password.pdf" . | |
| 4368 | - " --password=qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxc"}, | |
| 4369 | - {$td->REGEXP => ".*invalid password.*", $td->EXIT_STATUS => 2}); | |
| 4370 | - | |
| 4371 | -my $enc_base = undef; | |
| 4372 | -my $enc_n = 0; | |
| 4373 | -foreach my $d (@encrypted_files) | |
| 4374 | -{ | |
| 4375 | - ++$enc_n; | |
| 4376 | - my ($file, $pass, $xeflags, $P, $match_owner, $match_user, | |
| 4377 | - $accessible, $extract, $printlow, $printhigh, | |
| 4378 | - $modifyassembly, $modifyform, $modifyannot, | |
| 4379 | - $modifyother, $modifyall) = @$d; | |
| 4380 | - | |
| 4381 | - my $f = sub { $_[0] ? "allowed" : "not allowed" }; | |
| 4382 | - my $jf = sub { $_[0] ? "true" : "false" }; | |
| 4383 | - my $enc_details = ""; | |
| 4384 | - my $enc_json = | |
| 4385 | - "{\n" . | |
| 4386 | - " \"version\": 2,\n" . | |
| 4387 | - " \"parameters\": {\n" . | |
| 4388 | - " \"decodelevel\": \"generalized\"\n" . | |
| 4389 | - " },\n" . | |
| 4390 | - " \"encrypt\": {\n" . | |
| 4391 | - " \"capabilities\": {\n"; | |
| 4392 | - if ($match_owner) | |
| 4393 | - { | |
| 4394 | - $enc_details .= "Supplied password is owner password\n"; | |
| 4395 | - } | |
| 4396 | - if ($match_user) | |
| 4397 | - { | |
| 4398 | - $enc_details .= "Supplied password is user password\n"; | |
| 4399 | - } | |
| 4400 | - $enc_details .= | |
| 4401 | - "extract for accessibility: " . &$f($accessible) . "\n" . | |
| 4402 | - "extract for any purpose: " . &$f($extract) . "\n" . | |
| 4403 | - "print low resolution: " . &$f($printlow) . "\n" . | |
| 4404 | - "print high resolution: " . &$f($printhigh) . "\n" . | |
| 4405 | - "modify document assembly: " . &$f($modifyassembly) . "\n" . | |
| 4406 | - "modify forms: " . &$f($modifyform) . "\n" . | |
| 4407 | - "modify annotations: " . &$f($modifyannot) . "\n" . | |
| 4408 | - "modify other: " . &$f($modifyother) . "\n" . | |
| 4409 | - "modify anything: " . &$f($modifyall) . "\n"; | |
| 4410 | - $enc_json .= | |
| 4411 | - " \"accessibility\": " . &$jf($accessible) . ",\n" . | |
| 4412 | - " \"extract\": " . &$jf($extract) . ",\n" . | |
| 4413 | - " \"modify\": " . &$jf($modifyall) . ",\n" . | |
| 4414 | - " \"modifyannotations\": " . &$jf($modifyannot) . ",\n" . | |
| 4415 | - " \"modifyassembly\": " . &$jf($modifyassembly) . ",\n" . | |
| 4416 | - " \"modifyforms\": " . &$jf($modifyform) . ",\n" . | |
| 4417 | - " \"modifyother\": " . &$jf($modifyother) . ",\n" . | |
| 4418 | - " \"printhigh\": " . &$jf($printhigh) . ",\n" . | |
| 4419 | - " \"printlow\": " . &$jf($printlow) . "\n" . | |
| 4420 | - " },\n" . | |
| 4421 | - " \"encrypted\": true,\n" . | |
| 4422 | - " \"ownerpasswordmatched\": ---opm---,\n" . | |
| 4423 | - " \"parameters\": {\n" . | |
| 4424 | - " \"P\": ---P---,\n" . | |
| 4425 | - " \"R\": ---R---,\n" . | |
| 4426 | - " \"V\": ---V---,\n" . | |
| 4427 | - " \"bits\": ---bits---,\n" . | |
| 4428 | - " \"filemethod\": \"---method---\",\n" . | |
| 4429 | - " \"key\": null,\n" . | |
| 4430 | - " \"method\": \"---method---\",\n" . | |
| 4431 | - " \"streammethod\": \"---method---\",\n" . | |
| 4432 | - " \"stringmethod\": \"---method---\"\n" . | |
| 4433 | - " },\n" . | |
| 4434 | - " \"userpasswordmatched\": ---upm---\n" . | |
| 4435 | - " }\n" . | |
| 4436 | - "}\n"; | |
| 4437 | - if ($file =~ m/XI-/) | |
| 4438 | - { | |
| 4439 | - $enc_details .= | |
| 4440 | - "stream encryption method: AESv3\n" . | |
| 4441 | - "string encryption method: AESv3\n" . | |
| 4442 | - "file encryption method: AESv3\n"; | |
| 4443 | - } | |
| 4444 | - | |
| 4445 | - # Test writing to stdout | |
| 4446 | - $td->runtest("decrypt $file", | |
| 4447 | - {$td->COMMAND => | |
| 4448 | - "qpdf --static-id -qdf --object-streams=disable" . | |
| 4449 | - " --no-original-object-ids" . | |
| 4450 | - " --password=\"$pass\" enc-$file.pdf -" . | |
| 4451 | - " > $file.enc"}, | |
| 4452 | - {$td->STRING => "", | |
| 4453 | - $td->EXIT_STATUS => 0}); | |
| 4454 | - if ($file =~ m/base$/) | |
| 4455 | - { | |
| 4456 | - $enc_base = $file; | |
| 4457 | - $td->runtest("check ID", | |
| 4458 | - {$td->COMMAND => "perl check-ID.pl $file.enc"}, | |
| 4459 | - {$td->STRING => "ID okay\n", | |
| 4460 | - $td->EXIT_STATUS => 0}, | |
| 4461 | - $td->NORMALIZE_NEWLINES); | |
| 4462 | - } | |
| 4463 | - else | |
| 4464 | - { | |
| 4465 | - $td->runtest("check against base", | |
| 4466 | - {$td->COMMAND => | |
| 4467 | - "sh ./diff-encrypted $enc_base.enc $file.enc"}, | |
| 4468 | - {$td->STRING => "okay\n", | |
| 4469 | - $td->EXIT_STATUS => 0}, | |
| 4470 | - $td->NORMALIZE_NEWLINES); | |
| 4471 | - } | |
| 4472 | - if ($file =~ m/^(?:XI-)?R(\d),V(\d)(?:,U=(\w+))?(?:,O=(\w+))?$/) | |
| 4473 | - { | |
| 4474 | - my $R = $1; | |
| 4475 | - my $V = $2; | |
| 4476 | - my $upass = $3 || ""; | |
| 4477 | - my $opass = $4 || ""; | |
| 4478 | - my $bits = (($V == 5) ? 256 : ($V == 2) ? 128 : 40); | |
| 4479 | - my $method = $bits == 256 ? "AESv3" : "RC4"; | |
| 4480 | - my $opm = ($pass eq $opass ? "true" : "false"); | |
| 4481 | - my $upm = ($pass eq $upass ? "true" : "false"); | |
| 4482 | - $enc_json =~ s/---R---/$R/; | |
| 4483 | - $enc_json =~ s/---P---/$P/; | |
| 4484 | - $enc_json =~ s/---V---/$V/; | |
| 4485 | - $enc_json =~ s/---bits---/$bits/; | |
| 4486 | - $enc_json =~ s/---method---/$method/g; | |
| 4487 | - $enc_json =~ s/---opm---/$opm/; | |
| 4488 | - $enc_json =~ s/---upm---/$upm/; | |
| 4489 | - | |
| 4490 | - my $eflags = "--allow-weak-crypto" . | |
| 4491 | - " -encrypt \"$upass\" \"$opass\" $bits $xeflags --"; | |
| 4492 | - if (($opass eq "") && ($bits == 256)) | |
| 4493 | - { | |
| 4494 | - $eflags =~ s/--$/--allow-insecure --/; | |
| 4495 | - } | |
| 4496 | - if (($pass ne $upass) && ($V >= 5)) | |
| 4497 | - { | |
| 4498 | - # V >= 5 can no longer recover user password with owner | |
| 4499 | - # password. | |
| 4500 | - $upass = ""; | |
| 4501 | - } | |
| 4502 | - my $accessibility_warning = ""; | |
| 4503 | - if (($R > 3) && ($eflags =~ /accessibility=n/)) | |
| 4504 | - { | |
| 4505 | - $accessibility_warning = | |
| 4506 | - "qpdf: -accessibility=n is ignored" . | |
| 4507 | - " for modern encryption formats\n"; | |
| 4508 | - } | |
| 4509 | - $td->runtest("encrypt $file", | |
| 4510 | - {$td->COMMAND => | |
| 4511 | - "qpdf --static-id --no-original-object-ids -qdf" . | |
| 4512 | - " $eflags $file.enc $file.enc2"}, | |
| 4513 | - {$td->STRING => $accessibility_warning, | |
| 4514 | - $td->EXIT_STATUS => 0}, | |
| 4515 | - $td->NORMALIZE_NEWLINES); | |
| 4516 | - $td->runtest("check /P enc2 ($enc_n)", | |
| 4517 | - {$td->COMMAND => | |
| 4518 | - "qpdf --show-encryption --password=\"$pass\"" . | |
| 4519 | - " $file.enc2"}, | |
| 4520 | - {$td->STRING => "R = $R\nP = $P\n" . | |
| 4521 | - "User password = $upass\n$enc_details", | |
| 4522 | - $td->EXIT_STATUS => 0}, | |
| 4523 | - $td->NORMALIZE_NEWLINES); | |
| 4524 | - $td->runtest("json encrypt key ($enc_n)", | |
| 4525 | - {$td->COMMAND => | |
| 4526 | - "qpdf --json --json-key=encrypt" . | |
| 4527 | - " --password=\"$pass\"" . | |
| 4528 | - " $file.enc2"}, | |
| 4529 | - {$td->STRING => $enc_json, $td->EXIT_STATUS => 0}, | |
| 4530 | - $td->NORMALIZE_NEWLINES); | |
| 4531 | - $td->runtest("decrypt again", | |
| 4532 | - {$td->COMMAND => | |
| 4533 | - "qpdf --static-id --no-original-object-ids -qdf" . | |
| 4534 | - " --password=\"$pass\"" . | |
| 4535 | - " $file.enc2 $file.enc3"}, | |
| 4536 | - {$td->STRING => "", | |
| 4537 | - $td->EXIT_STATUS => 0}); | |
| 4538 | - $td->runtest("compare", | |
| 4539 | - {$td->FILE => "$file.enc"}, | |
| 4540 | - {$td->FILE => "$file.enc3"}); | |
| 4541 | - $td->runtest("preserve encryption", | |
| 4542 | - {$td->COMMAND => | |
| 4543 | - "qpdf --static-id --password=\"$pass\"" . | |
| 4544 | - " $file.enc2 $file.enc4"}, | |
| 4545 | - {$td->STRING => "", | |
| 4546 | - $td->EXIT_STATUS => 0}); | |
| 4547 | - $td->runtest("check /P enc4 ($enc_n)", | |
| 4548 | - {$td->COMMAND => | |
| 4549 | - "qpdf --show-encryption --password=\"$pass\"" . | |
| 4550 | - " $file.enc4"}, | |
| 4551 | - {$td->STRING => "R = $R\nP = $P\n" . | |
| 4552 | - "User password = $upass\n$enc_details", | |
| 4553 | - $td->EXIT_STATUS => 0}, | |
| 4554 | - $td->NORMALIZE_NEWLINES); | |
| 4555 | - } | |
| 4556 | -} | |
| 4557 | - | |
| 4558 | -$td->runtest("non-encrypted", | |
| 4559 | - {$td->COMMAND => "qpdf --show-encryption enc-base.pdf"}, | |
| 4560 | - {$td->STRING => "File is not encrypted\n", | |
| 4561 | - $td->EXIT_STATUS => 0}, | |
| 4562 | - $td->NORMALIZE_NEWLINES); | |
| 4563 | - | |
| 4564 | -$td->runtest("invalid password", | |
| 4565 | - {$td->COMMAND => "qpdf -qdf --password=quack" . | |
| 4566 | - " enc-R2,V1,U=view,O=view.pdf a.qdf"}, | |
| 4567 | - {$td->STRING => | |
| 4568 | - "qpdf: enc-R2,V1,U=view,O=view.pdf: invalid password\n", | |
| 4569 | - $td->EXIT_STATUS => 2}, | |
| 4570 | - $td->NORMALIZE_NEWLINES); | |
| 4571 | -$td->runtest("C API: invalid password", | |
| 4572 | - {$td->COMMAND => | |
| 4573 | - "qpdf-ctest 2 enc-R2,V1,U=view,O=view.pdf '' a.qdf"}, | |
| 4574 | - {$td->FILE => "c-invalid-password.out", $td->EXIT_STATUS => 0}, | |
| 4575 | - $td->NORMALIZE_NEWLINES); | |
| 4576 | - | |
| 4577 | -my @cenc = ( | |
| 4578 | - [11, 'hybrid-xref.pdf', "''", 'r2', "", ""], | |
| 4579 | - [12, 'hybrid-xref.pdf', "''", 'r3', "", ""], | |
| 4580 | - [15, 'hybrid-xref.pdf', "''", 'r4', "", ""], | |
| 4581 | - [17, 'hybrid-xref.pdf', "''", 'r5', "", "owner3"], | |
| 4582 | - [18, 'hybrid-xref.pdf', "''", 'r6', "", "user4"], | |
| 4583 | - [13, 'c-r2.pdf', 'user1', 'decrypt with user', | |
| 4584 | - "user password: user1\n", ""], | |
| 4585 | - [13, 'c-r3.pdf', 'owner2', 'decrypt with owner', | |
| 4586 | - "user password: user2\n", ""], | |
| 4587 | - [13, 'c-r5-in.pdf', 'user3', 'decrypt R5 with user', | |
| 4588 | - "user password: user3\n", ""], | |
| 4589 | - [13, 'c-r6-in.pdf', 'owner4', 'decrypt R6 with owner', | |
| 4590 | - "user password: \n", ""], | |
| 4591 | - ); | |
| 4592 | -$n_tests += 2 * @cenc; | |
| 4593 | - | |
| 4594 | -foreach my $d (@cenc) | |
| 4595 | -{ | |
| 4596 | - my ($n, $infile, $pass, $description, $output, $checkpass) = @$d; | |
| 4597 | - my $outfile = $description; | |
| 4598 | - $outfile =~ s/ /-/g; | |
| 4599 | - my $pdf_outfile = "c-$outfile.pdf"; | |
| 4600 | - my $check_outfile = "c-$outfile.out"; | |
| 4601 | - $td->runtest("C API encryption: $description", | |
| 4602 | - {$td->COMMAND => "qpdf-ctest $n $infile $pass a.pdf"}, | |
| 4603 | - {$td->STRING => $output . "C test $n done\n", | |
| 4604 | - $td->EXIT_STATUS => 0}, | |
| 4605 | - $td->NORMALIZE_NEWLINES); | |
| 4606 | - if (-f $pdf_outfile) | |
| 4607 | - { | |
| 4608 | - $td->runtest("check $description content", | |
| 4609 | - {$td->FILE => "a.pdf"}, | |
| 4610 | - {$td->FILE => $pdf_outfile}); | |
| 4611 | - } | |
| 4612 | - else | |
| 4613 | - { | |
| 4614 | - # QPDF doesn't provide any way to make the random bits in | |
| 4615 | - # /Perms static, so we have no way to predictably create a | |
| 4616 | - # /V=5 encrypted file. It's not worth adding this...the test | |
| 4617 | - # suite is adequate without having a statically predictable | |
| 4618 | - # file. | |
| 4619 | - $td->runtest("check $description", | |
| 4620 | - {$td->COMMAND => | |
| 4621 | - "qpdf --check a.pdf --password=$checkpass"}, | |
| 4622 | - {$td->FILE => $check_outfile, $td->EXIT_STATUS => 0}, | |
| 4623 | - $td->NORMALIZE_NEWLINES); | |
| 4624 | - } | |
| 4625 | -} | |
| 4626 | - | |
| 4627 | -# Test combinations of linearization and encryption. Note that we do | |
| 4628 | -# content checks on encrypted and linearized files in various | |
| 4629 | -# combinations below. Here we are just making sure that they are | |
| 4630 | -# linearized and/or encrypted as desired. | |
| 4631 | - | |
| 4632 | -$td->runtest("linearize encrypted file", | |
| 4633 | - {$td->COMMAND => "qpdf --linearize encrypted-with-images.pdf a.pdf"}, | |
| 4634 | - {$td->STRING => "", | |
| 4635 | - $td->EXIT_STATUS => 0}); | |
| 4636 | -$td->runtest("check encryption", | |
| 4637 | - {$td->COMMAND => "qpdf --show-encryption a.pdf", | |
| 4638 | - $td->FILTER => "grep -v allowed | grep -v Supplied"}, | |
| 4639 | - {$td->STRING => "R = 3\nP = -4\nUser password = \n", | |
| 4640 | - $td->EXIT_STATUS => 0}, | |
| 4641 | - $td->NORMALIZE_NEWLINES); | |
| 4642 | -$td->runtest("check linearization", | |
| 4643 | - {$td->COMMAND => "qpdf --check-linearization a.pdf"}, | |
| 4644 | - {$td->STRING => "a.pdf: no linearization errors\n", | |
| 4645 | - $td->EXIT_STATUS => 0}, | |
| 4646 | - $td->NORMALIZE_NEWLINES); | |
| 4647 | -$td->runtest("linearize and encrypt file", | |
| 4648 | - {$td->COMMAND => | |
| 4649 | - "qpdf --linearize --encrypt user owner 128 --use-aes=y --" . | |
| 4650 | - " lin-special.pdf a.pdf"}, | |
| 4651 | - {$td->STRING => "", | |
| 4652 | - $td->EXIT_STATUS => 0}); | |
| 4653 | -$td->runtest("check encryption", | |
| 4654 | - {$td->COMMAND => "qpdf --show-encryption --password=owner a.pdf", | |
| 4655 | - $td->FILTER => "grep -v allowed | grep -v method | grep -v Supplied"}, | |
| 4656 | - {$td->STRING => "R = 4\nP = -4\nUser password = user\n", | |
| 4657 | - $td->EXIT_STATUS => 0}, | |
| 4658 | - $td->NORMALIZE_NEWLINES); | |
| 4659 | -$td->runtest("check linearization", | |
| 4660 | - {$td->COMMAND => "qpdf --check-linearization" . | |
| 4661 | - " --password=user a.pdf"}, | |
| 4662 | - {$td->STRING => "a.pdf: no linearization errors\n", | |
| 4663 | - $td->EXIT_STATUS => 0}, | |
| 4664 | - $td->NORMALIZE_NEWLINES); | |
| 4665 | - | |
| 4666 | -# Test --check-linearization of non-linearized file | |
| 4667 | -$n_tests += 1; | |
| 4668 | -$td->runtest("check linearization of non-linearized file", | |
| 4669 | - {$td->COMMAND => "qpdf --check-linearization minimal.pdf"}, | |
| 4670 | - {$td->STRING => "minimal.pdf is not linearized\n", | |
| 4671 | - $td->EXIT_STATUS => 0}, | |
| 4672 | - $td->NORMALIZE_NEWLINES); | |
| 4673 | - | |
| 4674 | - | |
| 4675 | -# Test AES encryption in various ways. | |
| 4676 | -$n_tests += 18; | |
| 4677 | -$td->runtest("encrypt with AES", | |
| 4678 | - {$td->COMMAND => "qpdf --encrypt '' o 128 --use-aes=y --" . | |
| 4679 | - " enc-base.pdf a.pdf"}, | |
| 4680 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4681 | -$td->runtest("check encryption", | |
| 4682 | - {$td->COMMAND => "qpdf --show-encryption a.pdf", | |
| 4683 | - $td->FILTER => "grep -v allowed | grep -v method | grep -v Supplied"}, | |
| 4684 | - {$td->STRING => "R = 4\nP = -4\nUser password = \n", | |
| 4685 | - $td->EXIT_STATUS => 0}, | |
| 4686 | - $td->NORMALIZE_NEWLINES); | |
| 4687 | -$td->runtest("convert original to qdf", | |
| 4688 | - {$td->COMMAND => "qpdf --static-id --no-original-object-ids" . | |
| 4689 | - " --qdf --min-version=1.6 enc-base.pdf a.qdf"}, | |
| 4690 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4691 | -$td->runtest("convert encrypted to qdf", | |
| 4692 | - {$td->COMMAND => "qpdf --static-id --no-original-object-ids" . | |
| 4693 | - " --qdf a.pdf b.qdf"}, | |
| 4694 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4695 | -$td->runtest("compare files", | |
| 4696 | - {$td->FILE => 'a.qdf'}, | |
| 4697 | - {$td->FILE => 'b.qdf'}); | |
| 4698 | -$td->runtest("linearize with AES and object streams", | |
| 4699 | - {$td->COMMAND => "qpdf --encrypt '' o 128 --use-aes=y --" . | |
| 4700 | - " --linearize --object-streams=generate enc-base.pdf a.pdf"}, | |
| 4701 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4702 | -$td->runtest("check encryption", | |
| 4703 | - {$td->COMMAND => "qpdf --show-encryption a.pdf", | |
| 4704 | - $td->FILTER => "grep -v allowed | grep -v method | grep -v Supplied"}, | |
| 4705 | - {$td->STRING => "R = 4\nP = -4\nUser password = \n", | |
| 4706 | - $td->EXIT_STATUS => 0}, | |
| 4707 | - $td->NORMALIZE_NEWLINES); | |
| 4708 | -$td->runtest("linearize original", | |
| 4709 | - {$td->COMMAND => "qpdf --linearize --object-streams=generate" . | |
| 4710 | - " enc-base.pdf b.pdf"}, | |
| 4711 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4712 | -$td->runtest("convert linearized original to qdf", | |
| 4713 | - {$td->COMMAND => "qpdf --static-id --no-original-object-ids" . | |
| 4714 | - " --qdf --object-streams=generate --min-version=1.6" . | |
| 4715 | - " b.pdf a.qdf"}, | |
| 4716 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4717 | -$td->runtest("convert encrypted to qdf", | |
| 4718 | - {$td->COMMAND => "qpdf --static-id --no-original-object-ids" . | |
| 4719 | - " --qdf --object-streams=generate a.pdf b.qdf"}, | |
| 4720 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4721 | -$td->runtest("compare files", | |
| 4722 | - {$td->FILE => 'a.qdf'}, | |
| 4723 | - {$td->FILE => 'b.qdf'}); | |
| 4724 | -$td->runtest("force version on aes encrypted", | |
| 4725 | - {$td->COMMAND => "qpdf --force-version=1.4 a.pdf b.pdf"}, | |
| 4726 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4727 | -$td->runtest("check", | |
| 4728 | - {$td->COMMAND => "qpdf --check b.pdf"}, | |
| 4729 | - {$td->FILE => "aes-forced-check.out", | |
| 4730 | - $td->EXIT_STATUS => 0}, | |
| 4731 | - $td->NORMALIZE_NEWLINES); | |
| 4732 | -$td->runtest("make sure there is no xref stream", | |
| 4733 | - {$td->COMMAND => "grep /ObjStm b.pdf | wc -l"}, | |
| 4734 | - {$td->REGEXP => "\\s*0\\s*", $td->EXIT_STATUS => 0}, | |
| 4735 | - $td->NORMALIZE_NEWLINES); | |
| 4736 | -$td->runtest("encrypt with V=5,R=5", | |
| 4737 | - {$td->COMMAND => | |
| 4738 | - "qpdf --encrypt user owner 256 --force-R5 -- " . | |
| 4739 | - "minimal.pdf a.pdf"}, | |
| 4740 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4741 | -$td->runtest("check encryption", | |
| 4742 | - {$td->COMMAND => "qpdf --check a.pdf --password=owner"}, | |
| 4743 | - {$td->FILE => "V5R5.out", $td->EXIT_STATUS => 0}, | |
| 4744 | - $td->NORMALIZE_NEWLINES); | |
| 4745 | -$td->runtest("encrypt with V=5,R=6", | |
| 4746 | - {$td->COMMAND => | |
| 4747 | - "qpdf --encrypt user owner 256 -- " . | |
| 4748 | - "minimal.pdf a.pdf"}, | |
| 4749 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4750 | -$td->runtest("check encryption", | |
| 4751 | - {$td->COMMAND => "qpdf --check a.pdf --password=user"}, | |
| 4752 | - {$td->FILE => "V5R6.out", $td->EXIT_STATUS => 0}, | |
| 4753 | - $td->NORMALIZE_NEWLINES); | |
| 4754 | - | |
| 4755 | -# Look at some actual V4 files | |
| 4756 | -$n_tests += 17; | |
| 4757 | -foreach my $d (['--force-V4', 'V4'], | |
| 4758 | - ['--cleartext-metadata', 'V4-clearmeta'], | |
| 4759 | - ['--use-aes=y', 'V4-aes'], | |
| 4760 | - ['--cleartext-metadata --use-aes=y', 'V4-aes-clearmeta']) | |
| 4761 | -{ | |
| 4762 | - my ($args, $out) = @$d; | |
| 4763 | - $td->runtest("encrypt $args", | |
| 4764 | - {$td->COMMAND => "qpdf --static-aes-iv --static-id" . | |
| 4765 | - " --allow-weak-crypto --encrypt '' '' 128 $args --" . | |
| 4766 | - " enc-base.pdf a.pdf"}, | |
| 4767 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4768 | - $td->runtest("check output", | |
| 4769 | - {$td->FILE => "a.pdf"}, | |
| 4770 | - {$td->FILE => "$out.pdf"}); | |
| 4771 | - $td->runtest("show encryption", | |
| 4772 | - {$td->COMMAND => "qpdf --show-encryption a.pdf"}, | |
| 4773 | - {$td->FILE => "$out-encryption.out", $td->EXIT_STATUS => 0}, | |
| 4774 | - $td->NORMALIZE_NEWLINES); | |
| 4775 | -} | |
| 4776 | -# Crypt Filter | |
| 4777 | -$td->runtest("decrypt with crypt filter", | |
| 4778 | - {$td->COMMAND => "qpdf --decrypt --static-id" . | |
| 4779 | - " metadata-crypt-filter.pdf a.pdf"}, | |
| 4780 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4781 | -$td->runtest("check output", | |
| 4782 | - {$td->FILE => 'a.pdf'}, | |
| 4783 | - {$td->FILE => 'decrypted-crypt-filter.pdf'}); | |
| 4784 | -$td->runtest("nontrivial crypt filter", | |
| 4785 | - {$td->COMMAND => "qpdf --qdf --decrypt --static-id" . | |
| 4786 | - " nontrivial-crypt-filter.pdf --password=asdfqwer a.pdf"}, | |
| 4787 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4788 | -$td->runtest("check output", | |
| 4789 | - {$td->FILE => 'a.pdf'}, | |
| 4790 | - {$td->FILE => 'nontrivial-crypt-filter-decrypted.pdf'}); | |
| 4791 | -$td->runtest("show nontrivial EFF", | |
| 4792 | - {$td->COMMAND => "qpdf --show-encryption" . | |
| 4793 | - " nontrivial-crypt-filter.pdf --password=asdfqwer"}, | |
| 4794 | - {$td->FILE => "nontrivial-crypt-filter.out", | |
| 4795 | - $td->EXIT_STATUS => 0}, | |
| 4796 | - $td->NORMALIZE_NEWLINES); | |
| 4797 | - | |
| 4798 | -# Copy encryption parameters | |
| 4799 | -$n_tests += 10; | |
| 4800 | -$td->runtest("create reference qdf", | |
| 4801 | - {$td->COMMAND => | |
| 4802 | - "qpdf --qdf --no-original-object-ids minimal.pdf a.qdf"}, | |
| 4803 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4804 | -$td->runtest("create encrypted file", | |
| 4805 | - {$td->COMMAND => | |
| 4806 | - "qpdf --encrypt user owner 128 --use-aes=y --extract=n --" . | |
| 4807 | - " minimal.pdf a.pdf"}, | |
| 4808 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4809 | -$td->runtest("copy encryption parameters", | |
| 4810 | - {$td->COMMAND => "test_driver 30 minimal.pdf a.pdf"}, | |
| 4811 | - {$td->STRING => "test 30 done\n", $td->EXIT_STATUS => 0}, | |
| 4812 | - $td->NORMALIZE_NEWLINES); | |
| 4813 | -$td->runtest("check output encryption", | |
| 4814 | - {$td->COMMAND => "qpdf --show-encryption b.pdf --password=owner"}, | |
| 4815 | - {$td->FILE => "copied-encryption.out", | |
| 4816 | - $td->EXIT_STATUS => 0}, | |
| 4817 | - $td->NORMALIZE_NEWLINES); | |
| 4818 | -$td->runtest("convert to qdf", | |
| 4819 | - {$td->COMMAND => | |
| 4820 | - "qpdf --qdf b.pdf b.qdf" . | |
| 4821 | - " --password=owner --no-original-object-ids"}, | |
| 4822 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4823 | -$td->runtest("compare qdf", | |
| 4824 | - {$td->COMMAND => "sh ./diff-ignore-ID-version a.qdf b.qdf"}, | |
| 4825 | - {$td->STRING => "okay\n", $td->EXIT_STATUS => 0}, | |
| 4826 | - $td->NORMALIZE_NEWLINES); | |
| 4827 | -$td->runtest("copy encryption with qpdf", | |
| 4828 | - {$td->COMMAND => | |
| 4829 | - "qpdf --copy-encryption=a.pdf". | |
| 4830 | - " --encryption-file-password=user" . | |
| 4831 | - " minimal.pdf c.pdf"}, | |
| 4832 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 4833 | - $td->NORMALIZE_NEWLINES); | |
| 4834 | -$td->runtest("check output encryption", | |
| 4835 | - {$td->COMMAND => "qpdf --show-encryption c.pdf --password=owner"}, | |
| 4836 | - {$td->FILE => "copied-encryption.out", | |
| 4837 | - $td->EXIT_STATUS => 0}, | |
| 4838 | - $td->NORMALIZE_NEWLINES); | |
| 4839 | -$td->runtest("convert to qdf", | |
| 4840 | - {$td->COMMAND => | |
| 4841 | - "qpdf --qdf c.pdf c.qdf" . | |
| 4842 | - " --password=owner --no-original-object-ids"}, | |
| 4843 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4844 | -$td->runtest("compare qdf", | |
| 4845 | - {$td->COMMAND => "sh ./diff-ignore-ID-version a.qdf c.qdf"}, | |
| 4846 | - {$td->STRING => "okay\n", $td->EXIT_STATUS => 0}, | |
| 4847 | - $td->NORMALIZE_NEWLINES); | |
| 4848 | - | |
| 4849 | -# Files with attachments | |
| 4850 | -my @attachments = ( | |
| 4851 | - 'enc-XI-attachments-base.pdf', | |
| 4852 | - 'enc-XI-R6,V5,U=attachment,encrypted-attachments.pdf', | |
| 4853 | - 'enc-XI-R6,V5,U=view,attachments,cleartext-metadata.pdf'); | |
| 4854 | -$n_tests += 4 * @attachments + 3; | |
| 4855 | -foreach my $f (@attachments) | |
| 4856 | -{ | |
| 4857 | - my $pass = ''; | |
| 4858 | - my $tpass = ''; | |
| 4859 | - if ($f =~ m/U=([^,\.]+)/) | |
| 4860 | - { | |
| 4861 | - $pass = "--password=$1"; | |
| 4862 | - $tpass = $1; | |
| 4863 | - } | |
| 4864 | - $td->runtest("decrypt $f", | |
| 4865 | - {$td->COMMAND => "qpdf --decrypt $pass $f a.pdf"}, | |
| 4866 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4867 | - $td->runtest("extract attachments", | |
| 4868 | - {$td->COMMAND => "test_driver 35 a.pdf"}, | |
| 4869 | - {$td->FILE => "attachments.out", $td->EXIT_STATUS => 0}, | |
| 4870 | - $td->NORMALIZE_NEWLINES); | |
| 4871 | - $td->runtest("copy $f", | |
| 4872 | - {$td->COMMAND => "qpdf $pass $f a.pdf"}, | |
| 4873 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4874 | - $td->runtest("extract attachments", | |
| 4875 | - {$td->COMMAND => "test_driver 35 a.pdf $tpass"}, | |
| 4876 | - {$td->FILE => "attachments.out", $td->EXIT_STATUS => 0}, | |
| 4877 | - $td->NORMALIZE_NEWLINES); | |
| 4878 | -} | |
| 4879 | -$td->runtest("unfilterable with crypt", | |
| 4880 | - {$td->COMMAND => | |
| 4881 | - "test_driver 36 unfilterable-with-crypt.pdf attachment"}, | |
| 4882 | - {$td->FILE => "unfilterable-with-crypt-before.out", | |
| 4883 | - $td->EXIT_STATUS => 0}, | |
| 4884 | - $td->NORMALIZE_NEWLINES); | |
| 4885 | -unlink "a.pdf"; | |
| 4886 | -$td->runtest("decrypt file", | |
| 4887 | - {$td->COMMAND => "qpdf -decrypt --password=attachment" . | |
| 4888 | - " unfilterable-with-crypt.pdf a.pdf"}, | |
| 4889 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 4890 | -$td->runtest("copy of unfilterable with crypt", | |
| 4891 | - {$td->COMMAND => | |
| 4892 | - "test_driver 36 a.pdf attachment"}, | |
| 4893 | - {$td->FILE => "unfilterable-with-crypt-after.out", | |
| 4894 | - $td->EXIT_STATUS => 0}, | |
| 4895 | - $td->NORMALIZE_NEWLINES); | |
| 4896 | - | |
| 4897 | -# Raw encryption key | |
| 4898 | -my @enc_key = (['user', '--password=user3'], | |
| 4899 | - ['owner', '--password=owner3'], | |
| 4900 | - ['hex', '--password-is-hex-key --password=35ea16a48b6a3045133b69ac0906c2e8fb0a2cc97903ae17b51a5786ebdba020']); | |
| 4901 | -$n_tests += scalar(@enc_key); | |
| 4902 | -foreach my $d (@enc_key) | |
| 4903 | -{ | |
| 4904 | - my ($description, $pass) = @$d; | |
| 4905 | - $td->runtest("use/show encryption key ($description)", | |
| 4906 | - {$td->COMMAND => | |
| 4907 | - "qpdf --check --show-encryption-key c-r5-in.pdf $pass"}, | |
| 4908 | - {$td->FILE => "c-r5-key-$description.out", $td->EXIT_STATUS => 0}, | |
| 4909 | - $td->NORMALIZE_NEWLINES); | |
| 4910 | -} | |
| 4911 | - | |
| 4912 | -# Miscellaneous encryption tests | |
| 4913 | -$n_tests += 3; | |
| 4914 | - | |
| 4915 | -$td->runtest("set encryption before set filename", | |
| 4916 | - {$td->COMMAND => "test_driver 63 minimal.pdf"}, | |
| 4917 | - {$td->STRING => "test 63 done\n", $td->EXIT_STATUS => 0}, | |
| 4918 | - $td->NORMALIZE_NEWLINES); | |
| 4919 | -$td->runtest("check file's validity", | |
| 4920 | - {$td->COMMAND => "qpdf --check --password=u a.pdf"}, | |
| 4921 | - {$td->FILE => "encrypt-before-filename.out", | |
| 4922 | - $td->EXIT_STATUS => 0}, | |
| 4923 | - $td->NORMALIZE_NEWLINES); | |
| 4924 | -$td->runtest("handle missing/invalid Length", | |
| 4925 | - {$td->COMMAND => "qpdf --check bad-encryption-length.pdf"}, | |
| 4926 | - {$td->FILE => "bad-encryption-length.out", | |
| 4927 | - $td->EXIT_STATUS => 0}, | |
| 4928 | - $td->NORMALIZE_NEWLINES); | |
| 4929 | - | |
| 4930 | -show_ntests(); | |
| 4931 | -# ---------- | |
| 4932 | -$td->notify("--- Unicode Passwords ---"); | |
| 4933 | -# $n_tests incremented below | |
| 4934 | - | |
| 4935 | -# Files with each of these passwords when properly encoded have been | |
| 4936 | -# tested manually with multiple PDF viewers. Adobe Reader, chrome, | |
| 4937 | -# xpdf, and gv can open all of them except R3 with "single-byte", | |
| 4938 | -# which can be opened by xpdf and gv but not the others. As of | |
| 4939 | -# 2019-01-19, okular and atril (evince) are not able to open R=6 files | |
| 4940 | -# with Unicode passwords as generated by qpdf but can open the R=3 | |
| 4941 | -# files. | |
| 4942 | - | |
| 4943 | -# [bits, password-or-password-name, write-encoding, actual-encoding, xargs, | |
| 4944 | -# [[read-encoding, strict?, fail?, tried-others, xargs]]] | |
| 4945 | -my @unicode_pw_cases = ( | |
| 4946 | - [128, 'simple', 'pdf-doc', 'pdf-doc', '', | |
| 4947 | - [['utf8', 0, 0, 1, ''], | |
| 4948 | - ['utf8', 1, 1, 0, ''], | |
| 4949 | - ['pdf-doc', 1, 0, 0, ''], | |
| 4950 | - ]], | |
| 4951 | - [128, 'simple', 'utf8', 'utf8', '--password-mode=bytes', | |
| 4952 | - [['pdf-doc', 0, 0, 1, ''], | |
| 4953 | - ['pdf-doc', 1, 1, 0, ''], | |
| 4954 | - ['utf8', 1, 0, 0, ''], | |
| 4955 | - ]], | |
| 4956 | - [128, 'simple', 'utf8', 'pdf-doc', '--password-mode=unicode', | |
| 4957 | - [['pdf-doc', 1, 0, 0, ''], | |
| 4958 | - ]], | |
| 4959 | - [128, 'simple', 'utf8', 'pdf-doc', '--password-mode=auto', | |
| 4960 | - [['pdf-doc', 1, 0, 0, ''], | |
| 4961 | - ]], | |
| 4962 | - [128, 'single-byte', 'utf8', 'pdf-doc', '', | |
| 4963 | - [['pdf-doc', 1, 0, 0, ''], | |
| 4964 | - ['win-ansi', 0, 0, 1, ''], | |
| 4965 | - ]], | |
| 4966 | - [128, 'single-byte', 'utf8', 'pdf-doc', '--password-mode=unicode', | |
| 4967 | - [['pdf-doc', 1, 0, 0, ''], | |
| 4968 | - ['win-ansi', 0, 0, 1, ''], | |
| 4969 | - ]], | |
| 4970 | - [128, 'single-byte', 'win-ansi', '', '--password-mode=unicode', | |
| 4971 | - "supplied password is not valid UTF-8\n", | |
| 4972 | - ], | |
| 4973 | - [128, 'single-byte', 'win-ansi', 'win-ansi', '', | |
| 4974 | - [['win-ansi', 1, 0, 0, ''], | |
| 4975 | - ]], | |
| 4976 | - [128, 'single-byte', 'pdf-doc', 'pdf-doc', '', | |
| 4977 | - [['pdf-doc', 1, 0, 0, ''], | |
| 4978 | - ['win-ansi', 0, 0, 1, ''], | |
| 4979 | - ['pdf-doc-hex', 1, 0, 0, '--password-mode=hex-bytes'], | |
| 4980 | - ]], | |
| 4981 | - [128, 'complex', 'utf8', '', '--password-mode=unicode', | |
| 4982 | - "supplied password cannot be encoded for 40-bit or" . | |
| 4983 | - " 128-bit encryption formats\n" | |
| 4984 | - ], | |
| 4985 | - [128, 'complex', 'utf8', 'utf8', '--password-mode=bytes', | |
| 4986 | - [['utf8', 1, 0, 0, ''], | |
| 4987 | - ]], | |
| 4988 | - [256, 'single-byte', 'win-ansi', '', '--password-mode=unicode', | |
| 4989 | - "supplied password is not valid UTF-8\n", | |
| 4990 | - ], | |
| 4991 | - [256, 'single-byte', 'win-ansi', '', '--password-mode=auto', | |
| 4992 | - "supplied password is not a valid Unicode password, which is" . | |
| 4993 | - " required for 256-bit encryption; to really use this password," . | |
| 4994 | - " rerun with the --password-mode=bytes option\n", | |
| 4995 | - ], | |
| 4996 | - [256, 'single-byte', 'win-ansi', 'win-ansi', '--password-mode=bytes', | |
| 4997 | - [['utf8', 0, 0, 1, ''], | |
| 4998 | - ['utf8', 1, 1, 0, ''], | |
| 4999 | - ['win-ansi', 1, 0, 0, ''], | |
| 5000 | - ['win-ansi', 0, 0, 0, ''], | |
| 5001 | - ['pdf-doc', 0, 0, 1, ''], | |
| 5002 | - ['pdf-doc-hex', 0, 0, 1, '--password-mode=hex-bytes'], | |
| 5003 | - ]], | |
| 5004 | - [256, 'complex', 'utf8', 'utf8', '', | |
| 5005 | - [['utf8', 1, 0, 0, ''], | |
| 5006 | - ['utf8-hex', 1, 0, 0, '--password-mode=hex-bytes'], | |
| 5007 | - ]], | |
| 5008 | - [256, 'complex', 'utf8-hex', 'utf8', '--password-mode=hex-bytes', | |
| 5009 | - [['utf8', 1, 0, 0, ''], | |
| 5010 | - ['utf8-hex', 1, 0, 0, '--password-mode=hex-bytes'], | |
| 5011 | - ]], | |
| 5012 | - [256, 'complex', 'utf8', 'utf8', '--password-mode=unicode', | |
| 5013 | - [['utf8', 1, 0, 0, ''], | |
| 5014 | - ['password-arg-simple-utf8', 0, 1, 1, ''], | |
| 5015 | - ]], | |
| 5016 | - ); | |
| 5017 | - | |
| 5018 | -for my $d (@unicode_pw_cases) | |
| 5019 | -{ | |
| 5020 | - my $decode_cases = $d->[5]; | |
| 5021 | - $n_tests += 1; | |
| 5022 | - if (ref($decode_cases) eq 'ARRAY') | |
| 5023 | - { | |
| 5024 | - $n_tests += scalar(@$decode_cases); | |
| 5025 | - } | |
| 5026 | -} | |
| 5027 | - | |
| 5028 | -foreach my $d (@unicode_pw_cases) | |
| 5029 | -{ | |
| 5030 | - my ($bits, $pw, $w_encoding, $a_encoding, $xargs, $decode_cases) = @$d; | |
| 5031 | - my $w_pfile = "password-bare-$pw-$w_encoding"; | |
| 5032 | - my $upass; | |
| 5033 | - if (-f $w_pfile) | |
| 5034 | - { | |
| 5035 | - $upass = '@' . $w_pfile; | |
| 5036 | - } | |
| 5037 | - else | |
| 5038 | - { | |
| 5039 | - $upass = "$pw"; | |
| 5040 | - } | |
| 5041 | - my $outbase = "unicode-pw-$bits-$pw-$w_encoding-$xargs"; | |
| 5042 | - my $exp = ''; | |
| 5043 | - if (ref($decode_cases) ne 'ARRAY') | |
| 5044 | - { | |
| 5045 | - $exp = "qpdf: $decode_cases"; | |
| 5046 | - $decode_cases = []; | |
| 5047 | - } | |
| 5048 | - $td->runtest("encode $bits, $pw, $w_encoding", | |
| 5049 | - {$td->COMMAND => | |
| 5050 | - "qpdf $xargs --static-id --static-aes-iv" . | |
| 5051 | - " --allow-weak-crypto" . | |
| 5052 | - " --encrypt $upass o $bits -- minimal.pdf a.pdf"}, | |
| 5053 | - {$td->STRING => $exp, $td->EXIT_STATUS => ($exp ? 2 : 0)}, | |
| 5054 | - $td->NORMALIZE_NEWLINES); | |
| 5055 | - foreach my $d2 (@$decode_cases) | |
| 5056 | - { | |
| 5057 | - my ($r_encoding, $strict, $xfail, $tried_others, $r_xargs) = @$d2; | |
| 5058 | - my $r_pfile = "password-arg-$pw-$r_encoding"; | |
| 5059 | - if (! -f $r_pfile) | |
| 5060 | - { | |
| 5061 | - $r_pfile = $r_encoding; | |
| 5062 | - } | |
| 5063 | - my $r_output = ""; | |
| 5064 | - $r_output .= "trying other\n" if $tried_others; | |
| 5065 | - if ($xfail) | |
| 5066 | - { | |
| 5067 | - $r_output .= "qpdf: a.pdf: invalid password\n"; | |
| 5068 | - } | |
| 5069 | - else | |
| 5070 | - { | |
| 5071 | - $r_output .= "R = " . ($bits == 128 ? '3' : '6') . "\n"; | |
| 5072 | - open(F, "<password-bare-$pw-$a_encoding") or die; | |
| 5073 | - chomp (my $apw = <F>); | |
| 5074 | - close(F); | |
| 5075 | - $r_output .= "User password = $apw\n"; | |
| 5076 | - } | |
| 5077 | - $r_xargs .= $strict ? ' --suppress-password-recovery' : ''; | |
| 5078 | - $td->runtest("decrypt $pw, $r_encoding, strict=$strict", | |
| 5079 | - {$td->COMMAND => | |
| 5080 | - "qpdf --show-encryption --verbose" . | |
| 5081 | - " $r_xargs a.pdf \@$r_pfile", | |
| 5082 | - $td->FILTER => "perl show-unicode-encryption.pl"}, | |
| 5083 | - {$td->STRING => "$r_output", | |
| 5084 | - $td->EXIT_STATUS => ($xfail ? 2 : 0)}, | |
| 5085 | - $td->NORMALIZE_NEWLINES); | |
| 5086 | - } | |
| 5087 | -} | |
| 5088 | - | |
| 5089 | -$n_tests += 5; | |
| 5090 | - | |
| 5091 | -$td->runtest("bytes fallback warning", | |
| 5092 | - {$td->COMMAND => | |
| 5093 | - "qpdf --allow-weak-crypto" . | |
| 5094 | - " --encrypt \@password-bare-complex-utf8 o 128 --" . | |
| 5095 | - " minimal.pdf a.pdf"}, | |
| 5096 | - {$td->FILE => "bytes-fallback.out", $td->EXIT_STATUS => 0}, | |
| 5097 | - $td->NORMALIZE_NEWLINES); | |
| 5098 | -{ # local scope | |
| 5099 | - my $r_output = ""; | |
| 5100 | - $r_output .= "R = 3\n"; | |
| 5101 | - open(F, "<password-bare-complex-utf8") or die; | |
| 5102 | - chomp (my $apw = <F>); | |
| 5103 | - close(F); | |
| 5104 | - $r_output .= "User password = $apw\n"; | |
| 5105 | - $td->runtest("decrypt bytes fallback", | |
| 5106 | - {$td->COMMAND => | |
| 5107 | - "qpdf --show-encryption --verbose" . | |
| 5108 | - " a.pdf \@password-arg-complex-utf8" . | |
| 5109 | - " --password-mode=bytes", | |
| 5110 | - $td->FILTER => "perl show-unicode-encryption.pl"}, | |
| 5111 | - {$td->STRING => "$r_output", $td->EXIT_STATUS => 0}, | |
| 5112 | - $td->NORMALIZE_NEWLINES); | |
| 5113 | -} | |
| 5114 | - | |
| 5115 | -# Exercise passing Unicode passwords via the command line. This tests | |
| 5116 | -# wmain for Windows and assumes a UTF-8 locale for other platforms. | |
| 5117 | -$td->runtest("Unicode at CLI", | |
| 5118 | - {$td->COMMAND => | |
| 5119 | - "qpdf --encrypt ฯ สฌ 256 --" . | |
| 5120 | - " minimal.pdf a.pdf"}, | |
| 5121 | - {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 5122 | - $td->NORMALIZE_NEWLINES); | |
| 5123 | -$td->runtest("Decrypt using user password", | |
| 5124 | - {$td->COMMAND => "qpdf --show-encryption a.pdf --password=ฯ"}, | |
| 5125 | - {$td->FILE => "unicode-up.out", $td->EXIT_STATUS => 0}, | |
| 5126 | - $td->NORMALIZE_NEWLINES); | |
| 5127 | -$td->runtest("Decrypt using owner password", | |
| 5128 | - {$td->COMMAND => "qpdf --show-encryption a.pdf --password=สฌ"}, | |
| 5129 | - {$td->FILE => "unicode-op.out", $td->EXIT_STATUS => 0}, | |
| 5130 | - $td->NORMALIZE_NEWLINES); | |
| 5131 | - | |
| 5132 | -show_ntests(); | |
| 5133 | -# ---------- | |
| 5134 | -$td->notify("--- Check from C API ---"); | |
| 5135 | -my @c_check_types = qw(warn clear); | |
| 5136 | -$n_tests += scalar(@c_check_types); | |
| 5137 | - | |
| 5138 | -foreach my $i (@c_check_types) | |
| 5139 | -{ | |
| 5140 | - $td->runtest("C check $i", | |
| 5141 | - {$td->COMMAND => "qpdf-ctest 23 c-check-$i-in.pdf '' -"}, | |
| 5142 | - {$td->FILE => "c-check-$i.out", | |
| 5143 | - $td->EXIT_STATUS => 0}, | |
| 5144 | - $td->NORMALIZE_NEWLINES); | |
| 5145 | -} | |
| 5146 | - | |
| 5147 | -show_ntests(); | |
| 5148 | -# ---------- | |
| 5149 | -$td->notify("--- C API Object Handle ---"); | |
| 5150 | -$n_tests += 13; | |
| 5151 | - | |
| 5152 | -$td->runtest("C check object handles", | |
| 5153 | - {$td->COMMAND => "qpdf-ctest 24 minimal.pdf '' a.pdf"}, | |
| 5154 | - {$td->FILE => "c-object-handles.out", | |
| 5155 | - $td->EXIT_STATUS => 0}, | |
| 5156 | - $td->NORMALIZE_NEWLINES); | |
| 5157 | -$td->runtest("check output", | |
| 5158 | - {$td->FILE => 'a.pdf'}, | |
| 5159 | - {$td->FILE => 'c-object-handles-out.pdf'}); | |
| 5160 | - | |
| 5161 | -$td->runtest("C check object handle creation", | |
| 5162 | - {$td->COMMAND => "qpdf-ctest 25 minimal.pdf '' a.pdf"}, | |
| 5163 | - {$td->STRING => "C test 25 done\n", $td->EXIT_STATUS => 0}, | |
| 5164 | - $td->NORMALIZE_NEWLINES); | |
| 5165 | -$td->runtest("check output", | |
| 5166 | - {$td->FILE => 'a.pdf'}, | |
| 5167 | - {$td->FILE => 'c-object-handle-creation-out.pdf'}); | |
| 5168 | - | |
| 5169 | -$td->runtest("C indirect objects", | |
| 5170 | - {$td->COMMAND => "qpdf-ctest 33 minimal.pdf '' a.pdf"}, | |
| 5171 | - {$td->STRING => "C test 33 done\n", $td->EXIT_STATUS => 0}, | |
| 5172 | - $td->NORMALIZE_NEWLINES); | |
| 5173 | -$td->runtest("check output", | |
| 5174 | - {$td->FILE => 'a.pdf'}, | |
| 5175 | - {$td->FILE => 'c-indirect-objects-out.pdf'}); | |
| 5176 | - | |
| 5177 | -$td->runtest("C uninitialized objects", | |
| 5178 | - {$td->COMMAND => "qpdf-ctest 26 '' '' ''"}, | |
| 5179 | - {$td->FILE => "c-oh-uninitialized-objects.out", | |
| 5180 | - $td->EXIT_STATUS => 0}, | |
| 5181 | - $td->NORMALIZE_NEWLINES); | |
| 5182 | -$td->runtest("C string with embedded null", | |
| 5183 | - {$td->COMMAND => "qpdf-ctest 27 '' '' ''"}, | |
| 5184 | - {$td->STRING => "C test 27 done\n", $td->EXIT_STATUS => 0}, | |
| 5185 | - $td->NORMALIZE_NEWLINES); | |
| 5186 | -$td->runtest("C wrap and clone objects", | |
| 5187 | - {$td->COMMAND => "qpdf-ctest 28 minimal.pdf '' ''"}, | |
| 5188 | - {$td->STRING => "C test 28 done\n", $td->EXIT_STATUS => 0}, | |
| 5189 | - $td->NORMALIZE_NEWLINES); | |
| 5190 | -$td->runtest("C object handle errors", | |
| 5191 | - {$td->COMMAND => "qpdf-ctest 29 minimal.pdf '' ''"}, | |
| 5192 | - {$td->FILE => "c-oh-errors.out", $td->EXIT_STATUS => 0}, | |
| 5193 | - $td->NORMALIZE_NEWLINES); | |
| 5194 | -$td->runtest("C unhandled error warning", | |
| 5195 | - {$td->COMMAND => "qpdf-ctest 30 bad1.pdf '' ''"}, | |
| 5196 | - {$td->FILE => "c-unhandled-error.out", $td->EXIT_STATUS => 0}, | |
| 5197 | - $td->NORMALIZE_NEWLINES); | |
| 5198 | -$td->runtest("C type mismatch warning", | |
| 5199 | - {$td->COMMAND => "qpdf-ctest 31 minimal.pdf '' ''"}, | |
| 5200 | - {$td->FILE => "c-type-warning.out", $td->EXIT_STATUS => 0}, | |
| 5201 | - $td->NORMALIZE_NEWLINES); | |
| 5202 | -$td->runtest("C get object by ID", | |
| 5203 | - {$td->COMMAND => "qpdf-ctest 32 minimal.pdf '' ''"}, | |
| 5204 | - {$td->STRING => "C test 32 done\n", $td->EXIT_STATUS => 0}, | |
| 5205 | - $td->NORMALIZE_NEWLINES); | |
| 5206 | - | |
| 5207 | -show_ntests(); | |
| 5208 | -# ---------- | |
| 5209 | -$td->notify("--- C API Page Functions ---"); | |
| 5210 | -$n_tests += 5; | |
| 5211 | - | |
| 5212 | -$td->runtest("C page normal", | |
| 5213 | - {$td->COMMAND => | |
| 5214 | - "qpdf-ctest 34 11-pages.pdf '' a.pdf minimal.pdf"}, | |
| 5215 | - {$td->STRING => "C test 34 done\n", $td->EXIT_STATUS => 0}, | |
| 5216 | - $td->NORMALIZE_NEWLINES); | |
| 5217 | -$td->runtest("check output", | |
| 5218 | - {$td->FILE => 'a.pdf'}, | |
| 5219 | - {$td->FILE => 'c-pages.pdf'}); | |
| 5220 | - | |
| 5221 | -$td->runtest("C page errors", | |
| 5222 | - {$td->COMMAND => | |
| 5223 | - "qpdf-ctest 35 11-pages.pdf '' ''"}, | |
| 5224 | - {$td->FILE => "c-page-errors.out", $td->EXIT_STATUS => 0}, | |
| 5225 | - $td->NORMALIZE_NEWLINES); | |
| 5226 | -$td->runtest("C inherited page resources", | |
| 5227 | - {$td->COMMAND => | |
| 5228 | - "qpdf-ctest 36 inherited-rotate.pdf '' ''"}, | |
| 5229 | - {$td->STRING => "C test 36 done\n", $td->EXIT_STATUS => 0}, | |
| 5230 | - $td->NORMALIZE_NEWLINES); | |
| 5231 | -$td->runtest("C pages cache", | |
| 5232 | - {$td->COMMAND => | |
| 5233 | - "qpdf-ctest 37 11-pages.pdf '' ''"}, | |
| 5234 | - {$td->STRING => "C test 37 done\n", $td->EXIT_STATUS => 0}, | |
| 5235 | - $td->NORMALIZE_NEWLINES); | |
| 5236 | - | |
| 5237 | -show_ntests(); | |
| 5238 | -# ---------- | |
| 5239 | -$td->notify("--- C API Stream Functions ---"); | |
| 5240 | -$n_tests += 5; | |
| 5241 | - | |
| 5242 | -$td->runtest("C read streams", | |
| 5243 | - {$td->COMMAND => | |
| 5244 | - "qpdf-ctest 38 11-pages.pdf '' ''"}, | |
| 5245 | - {$td->FILE => "c-get-stream.out", $td->EXIT_STATUS => 0}, | |
| 5246 | - $td->NORMALIZE_NEWLINES); | |
| 5247 | - | |
| 5248 | -$td->runtest("C foreign object", | |
| 5249 | - {$td->COMMAND => | |
| 5250 | - "qpdf-ctest 39 11-pages.pdf '' a.pdf minimal.pdf"}, | |
| 5251 | - {$td->STRING => "C test 39 done\n", $td->EXIT_STATUS => 0}, | |
| 5252 | - $td->NORMALIZE_NEWLINES); | |
| 5253 | -$td->runtest("check output", | |
| 5254 | - {$td->FILE => 'a.pdf'}, | |
| 5255 | - {$td->FILE => 'c-foreign.pdf'}); | |
| 5256 | - | |
| 5257 | -$td->runtest("C new stream", | |
| 5258 | - {$td->COMMAND => | |
| 5259 | - "qpdf-ctest 40 minimal.pdf '' a.pdf"}, | |
| 5260 | - {$td->STRING => "C test 40 done\n", $td->EXIT_STATUS => 0}, | |
| 5261 | - $td->NORMALIZE_NEWLINES); | |
| 5262 | -$td->runtest("check output", | |
| 5263 | - {$td->FILE => 'a.pdf'}, | |
| 5264 | - {$td->FILE => 'c-new-stream.pdf'}); | |
| 5265 | -show_ntests(); | |
| 5266 | -# ---------- | |
| 5267 | -$td->notify("--- Content Preservation Tests ---"); | |
| 5268 | -# $n_tests incremented below | |
| 5269 | - | |
| 5270 | -my @files = ("encrypted-with-images.pdf", # encrypted | |
| 5271 | - "inline-images.pdf", | |
| 5272 | - "lin-special.pdf", | |
| 5273 | - "object-stream.pdf", | |
| 5274 | - "hybrid-xref.pdf"); | |
| 5275 | -my @flags = (["-qdf", # 1 | |
| 5276 | - "qdf"], | |
| 5277 | - ["-qdf --normalize-content=n", # 2 | |
| 5278 | - "qdf not normalized"], | |
| 5279 | - ["-qdf --stream-data=preserve", # 3 | |
| 5280 | - "qdf not uncompressed"], | |
| 5281 | - ["-qdf --stream-data=preserve --normalize-content=n", # 4 | |
| 5282 | - "qdf not normalized or uncompressed"], | |
| 5283 | - ["--stream-data=uncompress", # 5 | |
| 5284 | - "uncompresed"], | |
| 5285 | - ["--normalize-content=y", # 6 | |
| 5286 | - "normalized"], | |
| 5287 | - ["--stream-data=uncompress --normalize-content=y", # 7 | |
| 5288 | - "uncompressed and normalized"], | |
| 5289 | - ["-decrypt", # 8 | |
| 5290 | - "decrypted"], | |
| 5291 | - ["-linearize", # 9 | |
| 5292 | - "linearized"], | |
| 5293 | - ["-allow-weak-crypto -encrypt \"\" owner 128 --", # 10 | |
| 5294 | - "encrypted"], | |
| 5295 | - ["-linearize -allow-weak-crypto -encrypt \"\" o 128 --", # 11 | |
| 5296 | - "linearized and encrypted"], | |
| 5297 | - ["", # 12 | |
| 5298 | - "no arguments"], | |
| 5299 | - ); | |
| 5300 | - | |
| 5301 | -$n_tests += 1 + (@files * @flags * 2 * 3); | |
| 5302 | -$n_compare_pdfs += 1 + (@files * @flags * 2); | |
| 5303 | - | |
| 5304 | -foreach my $file (@files) | |
| 5305 | -{ | |
| 5306 | - my $base = basename($file, '.pdf'); | |
| 5307 | - | |
| 5308 | - foreach my $o (qw(disable generate)) | |
| 5309 | - { | |
| 5310 | - my $n = 0; | |
| 5311 | - my $oflags = "--object-streams=$o"; | |
| 5312 | - my $odescrip = "os:" . substr($o, 0, 1); | |
| 5313 | - my $osuf = ($o eq 'generate' ? "-ogen" : ""); | |
| 5314 | - foreach my $d (@flags) | |
| 5315 | - { | |
| 5316 | - my ($flags, $fdescrip) = @$d; | |
| 5317 | - ++$n; | |
| 5318 | - system("rm -f *.pnm"); | |
| 5319 | - | |
| 5320 | - $td->runtest("$file ($odescrip $fdescrip)", | |
| 5321 | - {$td->COMMAND => "qpdf $flags $oflags $file a.pdf"}, | |
| 5322 | - {$td->STRING => "", | |
| 5323 | - $td->EXIT_STATUS => 0}); | |
| 5324 | - | |
| 5325 | - $td->runtest("check status", | |
| 5326 | - {$td->COMMAND => "qpdf --check a.pdf"}, | |
| 5327 | - {$td->FILE => "$base.$n$osuf.check", | |
| 5328 | - $td->EXIT_STATUS => 0}, | |
| 5329 | - $td->NORMALIZE_NEWLINES); | |
| 5330 | - | |
| 5331 | - $td->runtest("check with C API", | |
| 5332 | - {$td->COMMAND => [qw(qpdf-ctest 1 a.pdf), "", ""]}, | |
| 5333 | - {$td->FILE => "$base.$n$osuf.c-check", | |
| 5334 | - $td->EXIT_STATUS => 0}, | |
| 5335 | - $td->NORMALIZE_NEWLINES); | |
| 5336 | - | |
| 5337 | - compare_pdfs($file, "a.pdf"); | |
| 5338 | - } | |
| 5339 | - flush_tiff_cache(); | |
| 5340 | - } | |
| 5341 | -} | |
| 5342 | - | |
| 5343 | -$td->runtest("convert inline-images to qdf", | |
| 5344 | - {$td->COMMAND => "qpdf --static-id --no-original-object-ids" . | |
| 5345 | - " --qdf inline-images.pdf a.pdf"}, | |
| 5346 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 5347 | - | |
| 5348 | -compare_pdfs("inline-images.pdf", "a.pdf"); | |
| 5349 | - | |
| 5350 | -show_ntests(); | |
| 5351 | -# ---------- | |
| 5352 | -$td->notify("--- Compression Level ---"); | |
| 5353 | -$n_tests += 4; | |
| 5354 | - | |
| 5355 | -check_pdf("recompress with level", | |
| 5356 | - "qpdf --static-id --recompress-flate --compression-level=9" . | |
| 5357 | - " --object-streams=generate minimal.pdf", | |
| 5358 | - "minimal-9.pdf", 0); | |
| 5359 | -check_pdf("recompress with level", | |
| 5360 | - "qpdf --static-id --recompress-flate --compression-level=1" . | |
| 5361 | - " --object-streams=generate minimal.pdf", | |
| 5362 | - "minimal-1.pdf", 0); | |
| 5363 | - | |
| 5364 | -show_ntests(); | |
| 5365 | -# ---------- | |
| 5366 | -$td->notify("--- Specialized filtering Tests ---"); | |
| 5367 | -$n_tests += 3; | |
| 5368 | -$n_compare_pdfs += 1; | |
| 5369 | - | |
| 5370 | -# The PDF file was submitted on bug #83 on github. All the PNG filters | |
| 5371 | -# are exercised. The test suite does not exercise PNG predictors with | |
| 5372 | -# LZW because I don't have a way to create such a file, but it's very | |
| 5373 | -# likely that it will work since the handling of the PNG filters is | |
| 5374 | -# separate from the regular decompression. | |
| 5375 | -$td->runtest("decode png-filtering", | |
| 5376 | - {$td->COMMAND => "qpdf --static-id" . | |
| 5377 | - " --compress-streams=n --decode-level=generalized" . | |
| 5378 | - " png-filters.pdf a.pdf"}, | |
| 5379 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 5380 | -$td->runtest("check output", | |
| 5381 | - {$td->FILE => "a.pdf"}, | |
| 5382 | - {$td->FILE => "png-filters-decoded.pdf"}); | |
| 5383 | -compare_pdfs("png-filters.pdf", "a.pdf"); | |
| 5384 | - | |
| 5385 | -$td->runtest("stream with tiff predictor", | |
| 5386 | - {$td->COMMAND => "qpdf --check tiff-predictor.pdf"}, | |
| 5387 | - {$td->FILE => "tiff-predictor.out", | |
| 5388 | - $td->EXIT_STATUS => 0}, | |
| 5389 | - $td->NORMALIZE_NEWLINES); | |
| 5390 | - | |
| 5391 | -show_ntests(); | |
| 5392 | -# ---------- | |
| 5393 | -$td->notify("--- fix-qdf Tests ---"); | |
| 5394 | -$n_tests += 5; | |
| 5395 | - | |
| 5396 | -for (my $n = 1; $n <= 2; ++$n) | |
| 5397 | -{ | |
| 5398 | - $td->runtest("fix-qdf $n", | |
| 5399 | - {$td->COMMAND => "fix-qdf fix$n.qdf"}, | |
| 5400 | - {$td->FILE => "fix$n.qdf.out", | |
| 5401 | - $td->EXIT_STATUS => 0}); | |
| 5402 | - | |
| 5403 | - $td->runtest("identity fix-qdf $n", | |
| 5404 | - {$td->COMMAND => "fix-qdf fix$n.qdf.out"}, | |
| 5405 | - {$td->FILE => "fix$n.qdf.out", | |
| 5406 | - $td->EXIT_STATUS => 0}); | |
| 5407 | -} | |
| 5408 | -$td->runtest("fix-qdf with big object stream", # > 255 objects in a stream | |
| 5409 | - {$td->COMMAND => "fix-qdf big-ostream.pdf"}, | |
| 5410 | - {$td->FILE => "big-ostream.pdf", | |
| 5411 | - $td->EXIT_STATUS => 0}); | |
| 5412 | - | |
| 5413 | -show_ntests(); | |
| 5414 | -# ---------- | |
| 5415 | -$td->notify("--- Signature Dictionary ---"); | |
| 5416 | -$n_tests += 6; | |
| 5417 | -foreach my $i (qw(preserve disable generate)) | |
| 5418 | -{ | |
| 5419 | - $td->runtest("sig dict contents hex (object-streams=$i)", | |
| 5420 | - {$td->COMMAND => | |
| 5421 | - "qpdf --object-streams=$i digitally-signed.pdf a.pdf"}, | |
| 5422 | - {$td->STRING => "", | |
| 5423 | - $td->EXIT_STATUS => 0}); | |
| 5424 | - # Use grep -f rather than writing something in test_driver because | |
| 5425 | - # the point of the test is to ensure that the contents appears in | |
| 5426 | - # the output file in the correct format. | |
| 5427 | - $td->runtest("find desired contents (object-streams=$i)", | |
| 5428 | - {$td->COMMAND => | |
| 5429 | - "grep -f digitally-signed-sig-dict-contents.out a.pdf"}, | |
| 5430 | - {$td->REGEXP => ".*", | |
| 5431 | - $td->EXIT_STATUS => 0}); | |
| 5432 | -} | |
| 5433 | - | |
| 5434 | -$n_tests += 4; | |
| 5435 | -foreach my $i (qw(preserve disable)) | |
| 5436 | -{ | |
| 5437 | - $td->runtest("non sig dict contents text string (object-streams=$i)", | |
| 5438 | - {$td->COMMAND => | |
| 5439 | - "qpdf --object-streams=$i comment-annotation.pdf a.pdf"}, | |
| 5440 | - {$td->STRING => "", | |
| 5441 | - $td->EXIT_STATUS => 0}); | |
| 5442 | - $td->runtest("find desired contents as non hex (object-streams=$i)", | |
| 5443 | - {$td->COMMAND => | |
| 5444 | - "grep \"/Contents (Salad)\" a.pdf"}, | |
| 5445 | - {$td->REGEXP => ".*", | |
| 5446 | - $td->EXIT_STATUS => 0}); | |
| 5447 | -} | |
| 5448 | - | |
| 5449 | -$n_tests += 2; | |
| 5450 | - $td->runtest("non sig dict contents text string (object-streams=generate)", | |
| 5451 | - {$td->COMMAND => | |
| 5452 | - "qpdf --object-streams=generate comment-annotation.pdf a.pdf"}, | |
| 5453 | - {$td->STRING => "", | |
| 5454 | - $td->EXIT_STATUS => 0}); | |
| 5455 | - $td->runtest("plain text not found due to compression (object-streams=generate)", | |
| 5456 | - {$td->COMMAND => | |
| 5457 | - "grep \"/Contents (Salad)\" a.pdf"}, | |
| 5458 | - {$td->REGEXP => ".*", | |
| 5459 | - $td->EXIT_STATUS => 1}); | |
| 5460 | - | |
| 5461 | -$n_tests += 12; | |
| 5462 | -foreach my $i (qw(40 128 256)) | |
| 5463 | -{ | |
| 5464 | - my $x = ""; | |
| 5465 | - if ($i < 256) | |
| 5466 | - { | |
| 5467 | - $x = "--allow-weak-crypto"; | |
| 5468 | - } | |
| 5469 | - $td->runtest("encrypt $i", | |
| 5470 | - {$td->COMMAND => | |
| 5471 | - "qpdf $x --encrypt '' o $i --" . | |
| 5472 | - " digitally-signed.pdf a.pdf"}, | |
| 5473 | - {$td->STRING => "", | |
| 5474 | - $td->EXIT_STATUS => 0}); | |
| 5475 | - $td->runtest("find desired contents (encrypt $i)", | |
| 5476 | - {$td->COMMAND => | |
| 5477 | - "grep -f digitally-signed-sig-dict-contents.out a.pdf"}, | |
| 5478 | - {$td->REGEXP => ".*", | |
| 5479 | - $td->EXIT_STATUS => 0}); | |
| 5480 | - $td->runtest("decrypt", | |
| 5481 | - {$td->COMMAND => | |
| 5482 | - "qpdf --decrypt a.pdf b.pdf"}, | |
| 5483 | - {$td->REGEXP => ".*", | |
| 5484 | - $td->EXIT_STATUS => 0}); | |
| 5485 | - $td->runtest("find desired contents (decrypt $i)", | |
| 5486 | - {$td->COMMAND => | |
| 5487 | - "grep -f digitally-signed-sig-dict-contents.out b.pdf"}, | |
| 5488 | - {$td->REGEXP => ".*", | |
| 5489 | - $td->EXIT_STATUS => 0}); | |
| 5490 | -} | |
| 5491 | - | |
| 5492 | -$n_tests += 15; | |
| 5493 | -foreach my $i (qw(40 128 256)) | |
| 5494 | -{ | |
| 5495 | - my $x = ""; | |
| 5496 | - if ($i < 256) | |
| 5497 | - { | |
| 5498 | - $x = "--allow-weak-crypto"; | |
| 5499 | - } | |
| 5500 | - $td->runtest("non sig dict encrypt $i", | |
| 5501 | - {$td->COMMAND => | |
| 5502 | - "qpdf $x --encrypt '' o $i --" . | |
| 5503 | - " comment-annotation.pdf a.pdf"}, | |
| 5504 | - {$td->STRING => "", | |
| 5505 | - $td->EXIT_STATUS => 0}); | |
| 5506 | - $td->runtest("plain text not found due to encryption (non sig dict encrypt $i)", | |
| 5507 | - {$td->COMMAND => | |
| 5508 | - "grep \"/Contents (Salad)\" a.pdf"}, | |
| 5509 | - {$td->REGEXP => ".*", | |
| 5510 | - $td->EXIT_STATUS => 1}); | |
| 5511 | - $td->runtest("find encrypted contents (non sig dict encrypt $i)", | |
| 5512 | - {$td->COMMAND => | |
| 5513 | - "grep \"/Contents <.*>\" a.pdf"}, | |
| 5514 | - {$td->REGEXP => ".*", | |
| 5515 | - $td->EXIT_STATUS => 0}); | |
| 5516 | - $td->runtest("non sig dict decrypt", | |
| 5517 | - {$td->COMMAND => | |
| 5518 | - "qpdf --decrypt a.pdf b.pdf"}, | |
| 5519 | - {$td->REGEXP => ".*", | |
| 5520 | - $td->EXIT_STATUS => 0}); | |
| 5521 | - $td->runtest("find desired contents (non sig dict decrypt $i)", | |
| 5522 | - {$td->COMMAND => | |
| 5523 | - "grep \"/Contents (Salad)\" b.pdf"}, | |
| 5524 | - {$td->REGEXP => ".*", | |
| 5525 | - $td->EXIT_STATUS => 0}); | |
| 5526 | -} | |
| 5527 | - | |
| 5528 | -show_ntests(); | |
| 5529 | -# ---------- | |
| 5530 | -$td->notify("--- Get XRef Table ---"); | |
| 5531 | -$n_tests += 2; | |
| 5532 | - | |
| 5533 | -$td->runtest("without object streams", | |
| 5534 | - {$td->COMMAND => "test_xref minimal.pdf"}, | |
| 5535 | - {$td->FILE => "minimal-xref.out", | |
| 5536 | - $td->EXIT_STATUS => 0}, | |
| 5537 | - $td->NORMALIZE_NEWLINES); | |
| 5538 | - | |
| 5539 | -$td->runtest("with object streams", | |
| 5540 | - {$td->COMMAND => "test_xref digitally-signed.pdf"}, | |
| 5541 | - {$td->FILE => "digitally-signed-xref.out", | |
| 5542 | - $td->EXIT_STATUS => 0}, | |
| 5543 | - $td->NORMALIZE_NEWLINES); | |
| 5544 | - | |
| 5545 | -show_ntests(); | |
| 5546 | -# ---------- | |
| 5547 | -$td->notify("--- Renumber Objects / XRef ---"); | |
| 5548 | -$n_tests += 8; | |
| 5549 | - | |
| 5550 | -$td->runtest("w/o objstm", | |
| 5551 | - {$td->COMMAND => "test_renumber minimal.pdf"}, | |
| 5552 | - {$td->REGEXP => "succeeded\n", | |
| 5553 | - $td->EXIT_STATUS => 0}, | |
| 5554 | - $td->NORMALIZE_NEWLINES); | |
| 5555 | - | |
| 5556 | -$td->runtest("w/ objstm", | |
| 5557 | - {$td->COMMAND => "test_renumber digitally-signed.pdf"}, | |
| 5558 | - {$td->REGEXP => "succeeded\n", | |
| 5559 | - $td->EXIT_STATUS => 0}, | |
| 5560 | - $td->NORMALIZE_NEWLINES); | |
| 5561 | - | |
| 5562 | -$td->runtest("w/o objstm, --object-streams=generate", | |
| 5563 | - {$td->COMMAND => | |
| 5564 | - "test_renumber --object-streams=generate minimal.pdf"}, | |
| 5565 | - {$td->REGEXP => "succeeded\n", | |
| 5566 | - $td->EXIT_STATUS => 0}, | |
| 5567 | - $td->NORMALIZE_NEWLINES); | |
| 5568 | - | |
| 5569 | -$td->runtest("w/ objstm, --object-streams=generate", | |
| 5570 | - {$td->COMMAND => | |
| 5571 | - "test_renumber --object-streams=generate digitally-signed.pdf"}, | |
| 5572 | - {$td->REGEXP => "succeeded\n", | |
| 5573 | - $td->EXIT_STATUS => 0}, | |
| 5574 | - $td->NORMALIZE_NEWLINES); | |
| 5575 | - | |
| 5576 | -$td->runtest("w/o objstm, --linearize", | |
| 5577 | - {$td->COMMAND => | |
| 5578 | - "test_renumber --linearize minimal.pdf"}, | |
| 5579 | - {$td->REGEXP => "succeeded\n", | |
| 5580 | - $td->EXIT_STATUS => 0}, | |
| 5581 | - $td->NORMALIZE_NEWLINES); | |
| 5582 | - | |
| 5583 | -$td->runtest("w/ objstm, --linearize", | |
| 5584 | - {$td->COMMAND => | |
| 5585 | - "test_renumber --linearize digitally-signed.pdf"}, | |
| 5586 | - {$td->REGEXP => "succeeded\n", | |
| 5587 | - $td->EXIT_STATUS => 0}, | |
| 5588 | - $td->NORMALIZE_NEWLINES); | |
| 5589 | - | |
| 5590 | -$td->runtest("w/o objstm, --preserve-unreferenced", | |
| 5591 | - {$td->COMMAND => | |
| 5592 | - "test_renumber --preserve-unreferenced minimal.pdf"}, | |
| 5593 | - {$td->REGEXP => "succeeded\n", | |
| 5594 | - $td->EXIT_STATUS => 0}, | |
| 5595 | - $td->NORMALIZE_NEWLINES); | |
| 5596 | - | |
| 5597 | -$td->runtest("w/ objstm, --preserve-unreferenced", | |
| 5598 | - {$td->COMMAND => | |
| 5599 | - "test_renumber --preserve-unreferenced digitally-signed.pdf"}, | |
| 5600 | - {$td->REGEXP => "succeeded\n", | |
| 5601 | - $td->EXIT_STATUS => 0}, | |
| 5602 | - $td->NORMALIZE_NEWLINES); | |
| 5603 | - | |
| 5604 | -show_ntests(); | |
| 5605 | -# ---------- | |
| 5606 | -$td->notify("--- Parsed Offset ---"); | |
| 5607 | -$n_tests += 2; | |
| 5608 | - | |
| 5609 | -$td->runtest("parsed offset without object streams", | |
| 5610 | - {$td->COMMAND => "test_parsedoffset minimal.pdf"}, | |
| 5611 | - {$td->FILE => "minimal-parsedoffset.out", | |
| 5612 | - $td->EXIT_STATUS => 0}, | |
| 5613 | - $td->NORMALIZE_NEWLINES); | |
| 5614 | - | |
| 5615 | -$td->runtest("parsed offset with object streams", | |
| 5616 | - {$td->COMMAND => "test_parsedoffset digitally-signed.pdf"}, | |
| 5617 | - {$td->FILE => "digitally-signed-parsedoffset.out", | |
| 5618 | - $td->EXIT_STATUS => 0}, | |
| 5619 | - $td->NORMALIZE_NEWLINES); | |
| 5620 | - | |
| 5621 | -show_ntests(); | |
| 5622 | -# ---------- | |
| 5623 | -$td->notify("--- Large File Tests ---"); | |
| 5624 | -my $nlarge = 1; | |
| 5625 | -if (defined $large_file_test_path) | |
| 5626 | -{ | |
| 5627 | - $nlarge = 2; | |
| 5628 | -} | |
| 5629 | -else | |
| 5630 | -{ | |
| 5631 | - $td->notify("--- Skipping tests on actual large files ---"); | |
| 5632 | -} | |
| 5633 | -$n_tests += $nlarge * 13; | |
| 5634 | -for (my $large = 0; $large < $nlarge; ++$large) | |
| 5635 | -{ | |
| 5636 | - if ($large) | |
| 5637 | - { | |
| 5638 | - $td->notify("--- Running tests on actual large files ---"); | |
| 5639 | - } | |
| 5640 | - else | |
| 5641 | - { | |
| 5642 | - $td->notify("--- Running large file tests on small files ---"); | |
| 5643 | - } | |
| 5644 | - my $size = ($large ? "large" : "small"); | |
| 5645 | - my $file = $large ? "$large_file_test_path/a.pdf" : "a.pdf"; | |
| 5646 | - $td->runtest("write test file", | |
| 5647 | - {$td->COMMAND => "test_large_file write $size '$file'"}, | |
| 5648 | - {$td->FILE => "large_file.out", $td->EXIT_STATUS => 0}, | |
| 5649 | - $td->NORMALIZE_NEWLINES); | |
| 5650 | - $td->runtest("read test file", | |
| 5651 | - {$td->COMMAND => "test_large_file read $size '$file'"}, | |
| 5652 | - {$td->FILE => "large_file.out", $td->EXIT_STATUS => 0}, | |
| 5653 | - $td->NORMALIZE_NEWLINES); | |
| 5654 | - $td->runtest("check", | |
| 5655 | - {$td->COMMAND => "qpdf --suppress-recovery --check '$file'", | |
| 5656 | - $td->FILTER => "grep -v checking"}, | |
| 5657 | - {$td->FILE => "large_file-check-normal.out", | |
| 5658 | - $td->EXIT_STATUS => 0}, | |
| 5659 | - $td->NORMALIZE_NEWLINES); | |
| 5660 | - | |
| 5661 | - for my $ostream (0, 1) | |
| 5662 | - { | |
| 5663 | - for my $linearize (0, 1) | |
| 5664 | - { | |
| 5665 | - if (($ostream == 0) && ($linearize == 0)) | |
| 5666 | - { | |
| 5667 | - # Original file has no object streams and is not linearized. | |
| 5668 | - next; | |
| 5669 | - } | |
| 5670 | - my $args = ""; | |
| 5671 | - my $omode = $ostream ? "generate" : "disable"; | |
| 5672 | - my $lin = $linearize ? "--linearize" : ""; | |
| 5673 | - my $newfile = "$file-new"; | |
| 5674 | - | |
| 5675 | - $td->runtest("transform: ostream=$ostream, linearize=$linearize", | |
| 5676 | - {$td->COMMAND => | |
| 5677 | - "qpdf --stream-data=preserve" . | |
| 5678 | - " --object-streams=$omode" . | |
| 5679 | - " $lin '$file' '$newfile'"}, | |
| 5680 | - {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 5681 | - $td->runtest("read: ostream=$ostream, linearize=$linearize", | |
| 5682 | - {$td->COMMAND => | |
| 5683 | - "test_large_file read $size '$newfile'"}, | |
| 5684 | - {$td->FILE => "large_file.out", $td->EXIT_STATUS => 0}, | |
| 5685 | - $td->NORMALIZE_NEWLINES); | |
| 5686 | - my $check_out = | |
| 5687 | - ($linearize | |
| 5688 | - ? ($ostream | |
| 5689 | - ? "large_file-check-ostream-linearized.out" | |
| 5690 | - : "large_file-check-linearized.out") | |
| 5691 | - : ($ostream | |
| 5692 | - ? "large_file-check-ostream.out" | |
| 5693 | - : "large_file-check-normal.out")); | |
| 5694 | - $td->runtest("check: ostream=$ostream, linearize=$linearize", | |
| 5695 | - {$td->COMMAND => | |
| 5696 | - "qpdf --suppress-recovery --check '$newfile'", | |
| 5697 | - $td->FILTER => "grep -v checking"}, | |
| 5698 | - {$td->FILE => $check_out, $td->EXIT_STATUS => 0}, | |
| 5699 | - $td->NORMALIZE_NEWLINES); | |
| 5700 | - unlink $newfile; | |
| 5701 | - } | |
| 5702 | - } | |
| 5703 | - | |
| 5704 | - # Clobber xref | |
| 5705 | - open(F, "+<$file") or die; | |
| 5706 | - seek(F, -50, 2); | |
| 5707 | - my $pos = tell F; | |
| 5708 | - my $buf; | |
| 5709 | - read(F, $buf, 50); | |
| 5710 | - die unless $buf =~ m/^(.*startxref\n)\d+/s; | |
| 5711 | - $pos += length($1); | |
| 5712 | - seek(F, $pos, 0) or die; | |
| 5713 | - print F "oops" or die; | |
| 5714 | - close(F); | |
| 5715 | - | |
| 5716 | - my $cmd = +{$td->COMMAND => "test_large_file read $size '$file'"}; | |
| 5717 | - if ($large) | |
| 5718 | - { | |
| 5719 | - $cmd->{$td->FILTER} = "sed -e 's,$large_file_test_path/,,'"; | |
| 5720 | - } | |
| 5721 | - $td->runtest("reconstruct xref table", | |
| 5722 | - $cmd, | |
| 5723 | - {$td->FILE => "large_file_xref_reconstruct.out", | |
| 5724 | - $td->EXIT_STATUS => 0}, | |
| 5725 | - $td->NORMALIZE_NEWLINES); | |
| 5726 | - unlink $file; | |
| 5727 | -} | |
| 5728 | -show_ntests(); | |
| 5729 | -# ---------- | |
| 5730 | - | |
| 5731 | -cleanup(); | |
| 5732 | - | |
| 5733 | -# See comments at beginning about calculation of number of tests. We | |
| 5734 | -# do it strictly based on static values, not as a by-product of | |
| 5735 | -# running the test suite. | |
| 5736 | -$td->report(calc_ntests()); | |
| 5737 | - | |
| 5738 | -sub calc_ntests | |
| 5739 | -{ | |
| 5740 | - my $result = $n_tests; | |
| 5741 | - if ($compare_images) | |
| 5742 | - { | |
| 5743 | - $result += 3 * ($n_compare_pdfs); | |
| 5744 | - } | |
| 5745 | - $result; | |
| 5746 | -} | |
| 5747 | - | |
| 5748 | -sub show_ntests | |
| 5749 | -{ | |
| 5750 | - if (0) | |
| 5751 | - { | |
| 5752 | - $td->emphasize("tests so far: ". calc_ntests()); | |
| 5753 | - } | |
| 5754 | - # Calling cleanup here helps to ensure that sections of the test | |
| 5755 | - # suite are isolated. | |
| 5756 | - cleanup(); | |
| 5757 | -} | |
| 5758 | - | |
| 5759 | -sub check_pdf | |
| 5760 | -{ | |
| 5761 | - my ($description, $command, $output, $status) = @_; | |
| 5762 | - unlink "a.pdf"; | |
| 5763 | - $td->runtest($description, | |
| 5764 | - {$td->COMMAND => "$command a.pdf"}, | |
| 5765 | - {$td->STRING => "", | |
| 5766 | - $td->EXIT_STATUS => $status}); | |
| 5767 | - $td->runtest("check output", | |
| 5768 | - {$td->FILE => "a.pdf"}, | |
| 5769 | - {$td->FILE => $output}); | |
| 5770 | -} | |
| 5771 | - | |
| 5772 | -sub flush_tiff_cache | |
| 5773 | -{ | |
| 5774 | - system("rm -rf tiff-cache"); | |
| 5775 | -} | |
| 5776 | - | |
| 5777 | -sub compare_pdfs | |
| 5778 | -{ | |
| 5779 | - return unless $compare_images; | |
| 5780 | - | |
| 5781 | - my ($f1, $f2, $exp) = @_; | |
| 5782 | - | |
| 5783 | - $exp = 0 unless defined $exp; | |
| 5784 | - | |
| 5785 | - system("rm -rf tif1 tif2"); | |
| 5786 | - | |
| 5787 | - mkdir "tiff-cache", 0777 unless -d "tiff-cache"; | |
| 5788 | - | |
| 5789 | - my $md5_1 = get_md5_checksum($f1); | |
| 5790 | - my $md5_2 = get_md5_checksum($f2); | |
| 5791 | - | |
| 5792 | - mkdir "tif1", 0777 or die; | |
| 5793 | - mkdir "tif2", 0777 or die; | |
| 5794 | - | |
| 5795 | - if (-f "tiff-cache/$md5_1.tif") | |
| 5796 | - { | |
| 5797 | - $td->runtest("get cached original file image", | |
| 5798 | - {$td->COMMAND => "cp tiff-cache/$md5_1.tif tif1/a.tif"}, | |
| 5799 | - {$td->STRING => "", | |
| 5800 | - $td->EXIT_STATUS => 0}); | |
| 5801 | - } | |
| 5802 | - else | |
| 5803 | - { | |
| 5804 | - # We discard gs's stderr since it has sometimes been known to | |
| 5805 | - # complain about files that are not bad. In particular, gs | |
| 5806 | - # 9.04 can't handle empty xref sections such as those found in | |
| 5807 | - # the hybrid xref cases. We don't really care whether gs | |
| 5808 | - # complains or not as long as it creates correct images. If | |
| 5809 | - # it doesn't create correct images, the test will fail, and we | |
| 5810 | - # can run manually to see the error message. If it does, then | |
| 5811 | - # we don't care about the warning. | |
| 5812 | - $td->runtest("convert original file to image", | |
| 5813 | - {$td->COMMAND => | |
| 5814 | - "(cd tif1;" . | |
| 5815 | - " gs 2>$devNull -q -dNOPAUSE -sDEVICE=tiff24nc" . | |
| 5816 | - " -sOutputFile=a.tif - < ../$f1)"}, | |
| 5817 | - {$td->STRING => "", | |
| 5818 | - $td->EXIT_STATUS => 0}); | |
| 5819 | - copy("tif1/a.tif", "tiff-cache/$md5_1.tif"); | |
| 5820 | - } | |
| 5821 | - | |
| 5822 | - if (-f "tiff-cache/$md5_2.tif") | |
| 5823 | - { | |
| 5824 | - $td->runtest("get cached new file image", | |
| 5825 | - {$td->COMMAND => "cp tiff-cache/$md5_2.tif tif2/a.tif"}, | |
| 5826 | - {$td->STRING => "", | |
| 5827 | - $td->EXIT_STATUS => 0}); | |
| 5828 | - } | |
| 5829 | - else | |
| 5830 | - { | |
| 5831 | - $td->runtest("convert new file to image", | |
| 5832 | - {$td->COMMAND => | |
| 5833 | - "(cd tif2;" . | |
| 5834 | - " gs 2>$devNull -q -dNOPAUSE -sDEVICE=tiff24nc" . | |
| 5835 | - " -sOutputFile=a.tif - < ../$f2)"}, | |
| 5836 | - {$td->STRING => "", | |
| 5837 | - $td->EXIT_STATUS => 0}); | |
| 5838 | - copy("tif2/a.tif", "tiff-cache/$md5_2.tif"); | |
| 5839 | - } | |
| 5840 | - | |
| 5841 | - $td->runtest("compare images", | |
| 5842 | - {$td->COMMAND => "tiffcmp -t tif1/a.tif tif2/a.tif"}, | |
| 5843 | - {$td->REGEXP => ".*", | |
| 5844 | - $td->EXIT_STATUS => $exp}); | |
| 5845 | - | |
| 5846 | - system("rm -rf tif1 tif2"); | |
| 5847 | -} | |
| 5848 | - | |
| 5849 | -sub check_metadata | |
| 5850 | -{ | |
| 5851 | - my ($file, $exp_encrypted, $exp_cleartext) = @_; | |
| 5852 | - my $out = "encrypted=$exp_encrypted; cleartext=$exp_cleartext\n" . | |
| 5853 | - "test 6 done\n"; | |
| 5854 | - $td->runtest("check metadata: $file", | |
| 5855 | - {$td->COMMAND => "test_driver 6 $file"}, | |
| 5856 | - {$td->STRING => $out, $td->EXIT_STATUS => 0}, | |
| 5857 | - $td->NORMALIZE_NEWLINES); | |
| 5858 | -} | |
| 5859 | - | |
| 5860 | -sub get_md5_checksum | |
| 5861 | -{ | |
| 5862 | - my $file = shift; | |
| 5863 | - open(F, "<$file") or fatal("can't open $file: $!"); | |
| 5864 | - binmode F; | |
| 5865 | - my $digest = Digest::MD5->new->addfile(*F)->hexdigest; | |
| 5866 | - close(F); | |
| 5867 | - $digest; | |
| 5868 | -} | |
| 5869 | - | |
| 5870 | -sub cleanup | |
| 5871 | -{ | |
| 5872 | - system("rm -rf a.json *.ps *.pnm ?.pdf ?.qdf *.enc* tif1 tif2 tiff-cache"); | |
| 5873 | - system("rm -rf *split-out* ???-kfo.pdf *.tmpout \@file.pdf auto-*"); | |
| 5874 | -} |
qpdf/qtest/qpdf_test_helpers.pm
0 โ 100644
| 1 | +use File::Spec; | |
| 2 | + | |
| 3 | +my $devNull = File::Spec->devnull(); | |
| 4 | + | |
| 5 | +my $compare_images = 0; | |
| 6 | +if ((exists $ENV{'QPDF_TEST_COMPARE_IMAGES'}) && | |
| 7 | + ($ENV{'QPDF_TEST_COMPARE_IMAGES'} eq '1')) | |
| 8 | +{ | |
| 9 | + $compare_images = 1; | |
| 10 | +} | |
| 11 | + | |
| 12 | +sub calc_ntests | |
| 13 | +{ | |
| 14 | + my ($n_tests, $n_compare_pdfs) = @_; | |
| 15 | + my $result = $n_tests; | |
| 16 | + if ($compare_images) | |
| 17 | + { | |
| 18 | + $result += 3 * ($n_compare_pdfs); | |
| 19 | + } | |
| 20 | + $result; | |
| 21 | +} | |
| 22 | + | |
| 23 | +sub check_pdf | |
| 24 | +{ | |
| 25 | + my ($td, $description, $command, $output, $status) = @_; | |
| 26 | + unlink "a.pdf"; | |
| 27 | + $td->runtest($description, | |
| 28 | + {$td->COMMAND => "$command a.pdf"}, | |
| 29 | + {$td->STRING => "", | |
| 30 | + $td->EXIT_STATUS => $status}); | |
| 31 | + $td->runtest("check output", | |
| 32 | + {$td->FILE => "a.pdf"}, | |
| 33 | + {$td->FILE => $output}); | |
| 34 | +} | |
| 35 | + | |
| 36 | +sub flush_tiff_cache | |
| 37 | +{ | |
| 38 | + system("rm -rf tiff-cache"); | |
| 39 | +} | |
| 40 | + | |
| 41 | +sub compare_pdfs | |
| 42 | +{ | |
| 43 | + return unless $compare_images; | |
| 44 | + | |
| 45 | + # Each call to compare_pdfs generates three tests. This is known | |
| 46 | + # in calc_ntests. | |
| 47 | + my ($td, $f1, $f2, $exp) = @_; | |
| 48 | + | |
| 49 | + $exp = 0 unless defined $exp; | |
| 50 | + | |
| 51 | + system("rm -rf tif1 tif2"); | |
| 52 | + | |
| 53 | + mkdir "tiff-cache", 0777 unless -d "tiff-cache"; | |
| 54 | + | |
| 55 | + my $md5_1 = get_md5_checksum($f1); | |
| 56 | + my $md5_2 = get_md5_checksum($f2); | |
| 57 | + | |
| 58 | + mkdir "tif1", 0777 or die; | |
| 59 | + mkdir "tif2", 0777 or die; | |
| 60 | + | |
| 61 | + if (-f "tiff-cache/$md5_1.tif") | |
| 62 | + { | |
| 63 | + $td->runtest("get cached original file image", | |
| 64 | + {$td->COMMAND => "cp tiff-cache/$md5_1.tif tif1/a.tif"}, | |
| 65 | + {$td->STRING => "", | |
| 66 | + $td->EXIT_STATUS => 0}); | |
| 67 | + } | |
| 68 | + else | |
| 69 | + { | |
| 70 | + # We discard gs's stderr since it has sometimes been known to | |
| 71 | + # complain about files that are not bad. In particular, gs | |
| 72 | + # 9.04 can't handle empty xref sections such as those found in | |
| 73 | + # the hybrid xref cases. We don't really care whether gs | |
| 74 | + # complains or not as long as it creates correct images. If | |
| 75 | + # it doesn't create correct images, the test will fail, and we | |
| 76 | + # can run manually to see the error message. If it does, then | |
| 77 | + # we don't care about the warning. | |
| 78 | + $td->runtest("convert original file to image", | |
| 79 | + {$td->COMMAND => | |
| 80 | + "(cd tif1;" . | |
| 81 | + " gs 2>$devNull -q -dNOPAUSE -sDEVICE=tiff24nc" . | |
| 82 | + " -sOutputFile=a.tif - < ../$f1)"}, | |
| 83 | + {$td->STRING => "", | |
| 84 | + $td->EXIT_STATUS => 0}); | |
| 85 | + copy("tif1/a.tif", "tiff-cache/$md5_1.tif"); | |
| 86 | + } | |
| 87 | + | |
| 88 | + if (-f "tiff-cache/$md5_2.tif") | |
| 89 | + { | |
| 90 | + $td->runtest("get cached new file image", | |
| 91 | + {$td->COMMAND => "cp tiff-cache/$md5_2.tif tif2/a.tif"}, | |
| 92 | + {$td->STRING => "", | |
| 93 | + $td->EXIT_STATUS => 0}); | |
| 94 | + } | |
| 95 | + else | |
| 96 | + { | |
| 97 | + $td->runtest("convert new file to image", | |
| 98 | + {$td->COMMAND => | |
| 99 | + "(cd tif2;" . | |
| 100 | + " gs 2>$devNull -q -dNOPAUSE -sDEVICE=tiff24nc" . | |
| 101 | + " -sOutputFile=a.tif - < ../$f2)"}, | |
| 102 | + {$td->STRING => "", | |
| 103 | + $td->EXIT_STATUS => 0}); | |
| 104 | + copy("tif2/a.tif", "tiff-cache/$md5_2.tif"); | |
| 105 | + } | |
| 106 | + | |
| 107 | + $td->runtest("compare images", | |
| 108 | + {$td->COMMAND => "tiffcmp -t tif1/a.tif tif2/a.tif"}, | |
| 109 | + {$td->REGEXP => ".*", | |
| 110 | + $td->EXIT_STATUS => $exp}); | |
| 111 | + | |
| 112 | + system("rm -rf tif1 tif2"); | |
| 113 | +} | |
| 114 | + | |
| 115 | +sub check_metadata | |
| 116 | +{ | |
| 117 | + my ($td, $file, $exp_encrypted, $exp_cleartext) = @_; | |
| 118 | + my $out = "encrypted=$exp_encrypted; cleartext=$exp_cleartext\n" . | |
| 119 | + "test 6 done\n"; | |
| 120 | + $td->runtest("check metadata: $file", | |
| 121 | + {$td->COMMAND => "test_driver 6 $file"}, | |
| 122 | + {$td->STRING => $out, $td->EXIT_STATUS => 0}, | |
| 123 | + $td->NORMALIZE_NEWLINES); | |
| 124 | +} | |
| 125 | + | |
| 126 | +sub get_md5_checksum | |
| 127 | +{ | |
| 128 | + my $file = shift; | |
| 129 | + open(F, "<$file") or fatal("can't open $file: $!"); | |
| 130 | + binmode F; | |
| 131 | + my $digest = Digest::MD5->new->addfile(*F)->hexdigest; | |
| 132 | + close(F); | |
| 133 | + $digest; | |
| 134 | +} | |
| 135 | + | |
| 136 | +sub cleanup | |
| 137 | +{ | |
| 138 | + system("rm -rf a.json *.ps *.pnm ?.pdf ?.qdf *.enc* tif1 tif2 tiff-cache"); | |
| 139 | + system("rm -rf *split-out* ???-kfo.pdf *.tmpout \@file.pdf auto-*"); | |
| 140 | +} | |
| 141 | + | |
| 142 | +1; | ... | ... |
qpdf/qtest/qpdfjob.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | +use File::Copy; | |
| 6 | + | |
| 7 | +unshift(@INC, '.'); | |
| 8 | +require qpdf_test_helpers; | |
| 9 | + | |
| 10 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 11 | + | |
| 12 | +require TestDriver; | |
| 13 | + | |
| 14 | +cleanup(); | |
| 15 | + | |
| 16 | +my $td = new TestDriver('qpdfjob'); | |
| 17 | + | |
| 18 | +open(F, ">auto-txt") or die; | |
| 19 | +print F "from file"; | |
| 20 | +close(F); | |
| 21 | + | |
| 22 | +my @bad_json = ( | |
| 23 | + "bare-option-false", | |
| 24 | + "choice-mismatch", | |
| 25 | + "encrypt-duplicate-key-length", | |
| 26 | + "encrypt-missing-password", | |
| 27 | + "encrypt-no-key-length", | |
| 28 | + "pages-no-file", | |
| 29 | + "schema-error", | |
| 30 | + "json-error" | |
| 31 | + ); | |
| 32 | +my @good_json = ( | |
| 33 | + "choice-match", | |
| 34 | + "input-file-password", | |
| 35 | + "empty-input", | |
| 36 | + "replace-input", | |
| 37 | + "encrypt-40", | |
| 38 | + "encrypt-128", | |
| 39 | + "encrypt-256-with-restrictions", | |
| 40 | + "add-attachments", | |
| 41 | + "copy-attachments", | |
| 42 | + "underlay-overlay", | |
| 43 | + "underlay-overlay-password", | |
| 44 | + "misc-options", | |
| 45 | + ); | |
| 46 | +my $n_tests = 10 + scalar(@bad_json) + (2 * scalar(@good_json)); | |
| 47 | + | |
| 48 | + | |
| 49 | +foreach my $i (@bad_json) | |
| 50 | +{ | |
| 51 | + $td->runtest("QPDFJob bad json: $i", | |
| 52 | + {$td->COMMAND => "qpdf --job-json-file=bad-json-$i.json"}, | |
| 53 | + {$td->FILE => "bad-$i-json.out", $td->EXIT_STATUS => 2}, | |
| 54 | + $td->NORMALIZE_NEWLINES); | |
| 55 | +} | |
| 56 | + | |
| 57 | +foreach my $i (@good_json) | |
| 58 | +{ | |
| 59 | + if ($i eq 'replace-input') | |
| 60 | + { | |
| 61 | + copy("minimal.pdf", 'a.pdf'); | |
| 62 | + } | |
| 63 | + $td->runtest("QPDFJob good json: $i", | |
| 64 | + {$td->COMMAND => "qpdf --job-json-file=job-json-$i.json"}, | |
| 65 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 66 | + $td->NORMALIZE_NEWLINES); | |
| 67 | + if ($i =~ m/encrypt-256/) | |
| 68 | + { | |
| 69 | + $td->runtest("check encryption $i", | |
| 70 | + {$td->COMMAND => | |
| 71 | + "qpdf a.pdf --password=u" . | |
| 72 | + " --job-json-file=job-show-encryption.json"}, | |
| 73 | + {$td->FILE => "job-json-$i.out", $td->EXIT_STATUS => 0}, | |
| 74 | + $td->NORMALIZE_NEWLINES); | |
| 75 | + } | |
| 76 | + else | |
| 77 | + { | |
| 78 | + $td->runtest("check good json $i output", | |
| 79 | + {$td->FILE => "a.pdf"}, | |
| 80 | + {$td->FILE => "job-json-$i.pdf"}); | |
| 81 | + } | |
| 82 | +} | |
| 83 | + | |
| 84 | + | |
| 85 | +$td->runtest("QPDFJob json partial", | |
| 86 | + {$td->COMMAND => "test_driver 83 - job-partial.json"}, | |
| 87 | + {$td->FILE => "job-partial-json.out", $td->EXIT_STATUS => 0}, | |
| 88 | + $td->NORMALIZE_NEWLINES); | |
| 89 | +$td->runtest("QPDFJob API", | |
| 90 | + {$td->COMMAND => "test_driver 84 -"}, | |
| 91 | + {$td->FILE => "job-api.out", $td->EXIT_STATUS => 0}, | |
| 92 | + $td->NORMALIZE_NEWLINES); | |
| 93 | +$td->runtest("check output", | |
| 94 | + {$td->FILE => "a.pdf"}, | |
| 95 | + {$td->FILE => "test84.pdf"}); | |
| 96 | +$td->runtest("json output from job", | |
| 97 | + {$td->COMMAND => "qpdf --job-json-file=job-json-output.json"}, | |
| 98 | + {$td->FILE => "job-json-output.out.json", $td->EXIT_STATUS => 0}, | |
| 99 | + $td->NORMALIZE_NEWLINES); | |
| 100 | + | |
| 101 | +$td->runtest("C job API", | |
| 102 | + {$td->COMMAND => "qpdfjob-ctest"}, | |
| 103 | + {$td->FILE => "qpdfjob-ctest.out", $td->EXIT_STATUS => 0}, | |
| 104 | + $td->NORMALIZE_NEWLINES); | |
| 105 | +foreach my $i (['a.pdf', 1], ['b.pdf', 2], ['c.pdf', 3]) | |
| 106 | +{ | |
| 107 | + $td->runtest("check output", | |
| 108 | + {$td->FILE => $i->[0]}, | |
| 109 | + {$td->FILE => "qpdfjob-ctest$i->[1].pdf"}); | |
| 110 | +} | |
| 111 | +my $wide_out = `qpdfjob-ctest wide`; | |
| 112 | +$td->runtest("qpdfjob-ctest wide", | |
| 113 | + {$td->STRING => "$?: $wide_out"}, | |
| 114 | + {$td->REGEXP => "0: (wide test passed|skipped wide)\n"}, | |
| 115 | + $td->NORMALIZE_NEWLINES); | |
| 116 | +if ($wide_out =~ m/skipped/) | |
| 117 | +{ | |
| 118 | + $td->runtest("skipped wide", | |
| 119 | + {$td->STRING => "yes"}, | |
| 120 | + {$td->STRING => "yes"}); | |
| 121 | +} | |
| 122 | +else | |
| 123 | +{ | |
| 124 | + $td->runtest("check output", | |
| 125 | + {$td->FILE => "a.pdf"}, | |
| 126 | + {$td->FILE => "qpdfjob-ctest-wide.pdf"}); | |
| 127 | +} | |
| 128 | + | |
| 129 | +cleanup(); | |
| 130 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/renumber_objects.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('renumber_objects'); | |
| 16 | + | |
| 17 | +my $n_tests = 8; | |
| 18 | + | |
| 19 | +$td->runtest("w/o objstm", | |
| 20 | + {$td->COMMAND => "test_renumber minimal.pdf"}, | |
| 21 | + {$td->REGEXP => "succeeded\n", | |
| 22 | + $td->EXIT_STATUS => 0}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | + | |
| 25 | +$td->runtest("w/ objstm", | |
| 26 | + {$td->COMMAND => "test_renumber digitally-signed.pdf"}, | |
| 27 | + {$td->REGEXP => "succeeded\n", | |
| 28 | + $td->EXIT_STATUS => 0}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | + | |
| 31 | +$td->runtest("w/o objstm, --object-streams=generate", | |
| 32 | + {$td->COMMAND => | |
| 33 | + "test_renumber --object-streams=generate minimal.pdf"}, | |
| 34 | + {$td->REGEXP => "succeeded\n", | |
| 35 | + $td->EXIT_STATUS => 0}, | |
| 36 | + $td->NORMALIZE_NEWLINES); | |
| 37 | + | |
| 38 | +$td->runtest("w/ objstm, --object-streams=generate", | |
| 39 | + {$td->COMMAND => | |
| 40 | + "test_renumber --object-streams=generate digitally-signed.pdf"}, | |
| 41 | + {$td->REGEXP => "succeeded\n", | |
| 42 | + $td->EXIT_STATUS => 0}, | |
| 43 | + $td->NORMALIZE_NEWLINES); | |
| 44 | + | |
| 45 | +$td->runtest("w/o objstm, --linearize", | |
| 46 | + {$td->COMMAND => | |
| 47 | + "test_renumber --linearize minimal.pdf"}, | |
| 48 | + {$td->REGEXP => "succeeded\n", | |
| 49 | + $td->EXIT_STATUS => 0}, | |
| 50 | + $td->NORMALIZE_NEWLINES); | |
| 51 | + | |
| 52 | +$td->runtest("w/ objstm, --linearize", | |
| 53 | + {$td->COMMAND => | |
| 54 | + "test_renumber --linearize digitally-signed.pdf"}, | |
| 55 | + {$td->REGEXP => "succeeded\n", | |
| 56 | + $td->EXIT_STATUS => 0}, | |
| 57 | + $td->NORMALIZE_NEWLINES); | |
| 58 | + | |
| 59 | +$td->runtest("w/o objstm, --preserve-unreferenced", | |
| 60 | + {$td->COMMAND => | |
| 61 | + "test_renumber --preserve-unreferenced minimal.pdf"}, | |
| 62 | + {$td->REGEXP => "succeeded\n", | |
| 63 | + $td->EXIT_STATUS => 0}, | |
| 64 | + $td->NORMALIZE_NEWLINES); | |
| 65 | + | |
| 66 | +$td->runtest("w/ objstm, --preserve-unreferenced", | |
| 67 | + {$td->COMMAND => | |
| 68 | + "test_renumber --preserve-unreferenced digitally-signed.pdf"}, | |
| 69 | + {$td->REGEXP => "succeeded\n", | |
| 70 | + $td->EXIT_STATUS => 0}, | |
| 71 | + $td->NORMALIZE_NEWLINES); | |
| 72 | + | |
| 73 | +cleanup(); | |
| 74 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/replace_input.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('replace_input'); | |
| 16 | + | |
| 17 | +my $n_tests = 8; | |
| 18 | + | |
| 19 | +# Use Unicode file names to test replace input so we can be sure it | |
| 20 | +# works for that case. | |
| 21 | +$td->runtest("create unicode filenames", | |
| 22 | + {$td->COMMAND => "test_unicode_filenames"}, | |
| 23 | + {$td->STRING => "created Unicode filenames\n", | |
| 24 | + $td->EXIT_STATUS => 0}, | |
| 25 | + $td->NORMALIZE_NEWLINES); | |
| 26 | + | |
| 27 | +foreach my $d (['auto-รผ', 1], ['auto-รถฯ', 2]) | |
| 28 | +{ | |
| 29 | + my ($u, $n) = @$d; | |
| 30 | + $td->runtest("replace input $u", | |
| 31 | + {$td->COMMAND => "qpdf --deterministic-id" . | |
| 32 | + " --object-streams=generate --replace-input ./$u.pdf"}, | |
| 33 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 34 | + $td->NORMALIZE_NEWLINES); | |
| 35 | + $td->runtest("check output ($u)", | |
| 36 | + {$td->FILE => "$u.pdf"}, | |
| 37 | + {$td->FILE => "replace-input.pdf"}, | |
| 38 | + $td->NORMALIZE_NEWLINES); | |
| 39 | +} | |
| 40 | + | |
| 41 | +system("cp xref-with-short-size.pdf auto-warn.pdf") == 0 or die; | |
| 42 | +$td->runtest("replace input with warnings", | |
| 43 | + {$td->COMMAND => | |
| 44 | + "qpdf --deterministic-id --replace-input ./auto-warn.pdf"}, | |
| 45 | + {$td->FILE => "replace-warn.out", $td->EXIT_STATUS => 3}, | |
| 46 | + $td->NORMALIZE_NEWLINES); | |
| 47 | + | |
| 48 | +$td->runtest("check output", | |
| 49 | + {$td->FILE => "auto-warn.pdf"}, | |
| 50 | + {$td->FILE => "warn-replace.pdf"}); | |
| 51 | +$td->runtest("check orig output", | |
| 52 | + {$td->FILE => "auto-warn.pdf.~qpdf-orig"}, | |
| 53 | + {$td->FILE => "xref-with-short-size.pdf"}); | |
| 54 | + | |
| 55 | +cleanup(); | |
| 56 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/rotate_pages.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('rotate_pages'); | |
| 16 | + | |
| 17 | +my $n_tests = 18; | |
| 18 | + | |
| 19 | +# Do absolute, positive, and negative on ranges that include | |
| 20 | +# inherited and non-inherited. | |
| 21 | +# Pages 11-15 inherit /Rotate 90 | |
| 22 | +# Pages 1 and 2 have explicit /Rotate 270 | |
| 23 | +# Pages 16 and 17 have explicit /Rotate 180 | |
| 24 | + | |
| 25 | +$td->runtest("page rotation", | |
| 26 | + {$td->COMMAND => "qpdf --static-id to-rotate.pdf a.pdf" . | |
| 27 | + " --rotate=+90:1,4,11,16" . | |
| 28 | + " --rotate=180:2,5,12-13" . | |
| 29 | + " --rotate=-90:3,15,17,18"}, | |
| 30 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 31 | +$td->runtest("check output", | |
| 32 | + {$td->FILE => "a.pdf"}, | |
| 33 | + {$td->FILE => "rotated.pdf"}); | |
| 34 | + | |
| 35 | +$td->runtest("remove rotation", | |
| 36 | + {$td->COMMAND => "qpdf --static-id rotated.pdf a.pdf" . | |
| 37 | + " --qdf --no-original-object-ids --rotate=0"}, | |
| 38 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 39 | +$td->runtest("check output", | |
| 40 | + {$td->FILE => "a.pdf"}, | |
| 41 | + {$td->FILE => "unrotated.pdf"}); | |
| 42 | + | |
| 43 | +$td->runtest("rotate all pages", | |
| 44 | + {$td->COMMAND => | |
| 45 | + "qpdf --static-id --rotate=180 minimal.pdf a.pdf"}, | |
| 46 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 47 | +$td->runtest("check output", | |
| 48 | + {$td->FILE => "a.pdf"}, | |
| 49 | + {$td->FILE => "minimal-rotated.pdf"}); | |
| 50 | + | |
| 51 | +$td->runtest("flatten with inherited rotate", | |
| 52 | + {$td->COMMAND => | |
| 53 | + "qpdf --static-id --flatten-rotation" . | |
| 54 | + " inherited-rotate.pdf a.pdf"}, | |
| 55 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 56 | +$td->runtest("check output", | |
| 57 | + {$td->FILE => "a.pdf"}, | |
| 58 | + {$td->FILE => "inherited-flattened.pdf"}); | |
| 59 | + | |
| 60 | +foreach my $angle (qw(90 180 270)) | |
| 61 | +{ | |
| 62 | + $td->runtest("rotate annotations", | |
| 63 | + {$td->COMMAND => | |
| 64 | + "qpdf --static-id --qdf --rotate=$angle" . | |
| 65 | + " --flatten-rotation --no-original-object-ids" . | |
| 66 | + " form-fields-and-annotations.pdf a.pdf"}, | |
| 67 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 68 | + $td->runtest("check output (flatten $angle)", | |
| 69 | + {$td->FILE => "a.pdf"}, | |
| 70 | + {$td->FILE => "annotations-rotated-$angle.pdf"}); | |
| 71 | +} | |
| 72 | + | |
| 73 | +# The file form-fields-and-annotations-shared.pdf contains some | |
| 74 | +# annotations that appear in multiple pages /Annots, some non-shared | |
| 75 | +# things that share appearance streams, some form fields appear on | |
| 76 | +# multiple pages, and an indirect /Annotations array. It is out of | |
| 77 | +# spec in several ways but still works in most viewers. These test | |
| 78 | +# make sure we don't make anything worse and also end up exercising | |
| 79 | +# some cases of things being copied more than once, though we also | |
| 80 | +# exercise that with legitimate test cases using overlay. | |
| 81 | + | |
| 82 | +$td->runtest("shared annotations 1 page", | |
| 83 | + {$td->COMMAND => | |
| 84 | + "qpdf --qdf --no-original-object-ids --static-id" . | |
| 85 | + " --rotate=90:1 form-fields-and-annotations-shared.pdf" . | |
| 86 | + " a.pdf --flatten-rotation"}, | |
| 87 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 88 | + $td->NORMALIZE_NEWLINES); | |
| 89 | +$td->runtest("check output", | |
| 90 | + {$td->FILE => "a.pdf"}, | |
| 91 | + {$td->FILE => "rotated-shared-annotations-1.pdf"}); | |
| 92 | +$td->runtest("shared annotations 2 pages", | |
| 93 | + {$td->COMMAND => | |
| 94 | + "qpdf --qdf --no-original-object-ids --static-id" . | |
| 95 | + " --rotate=90:1,2 form-fields-and-annotations-shared.pdf" . | |
| 96 | + " a.pdf --flatten-rotation"}, | |
| 97 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 98 | + $td->NORMALIZE_NEWLINES); | |
| 99 | +$td->runtest("check output", | |
| 100 | + {$td->FILE => "a.pdf"}, | |
| 101 | + {$td->FILE => "rotated-shared-annotations-2.pdf"}); | |
| 102 | + | |
| 103 | +cleanup(); | |
| 104 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/signature_dictionary.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('signature_dictionary'); | |
| 16 | + | |
| 17 | +my $n_tests = 0; | |
| 18 | + | |
| 19 | +$n_tests += 6; | |
| 20 | +foreach my $i (qw(preserve disable generate)) | |
| 21 | +{ | |
| 22 | + $td->runtest("sig dict contents hex (object-streams=$i)", | |
| 23 | + {$td->COMMAND => | |
| 24 | + "qpdf --object-streams=$i digitally-signed.pdf a.pdf"}, | |
| 25 | + {$td->STRING => "", | |
| 26 | + $td->EXIT_STATUS => 0}); | |
| 27 | + # Use grep -f rather than writing something in test_driver because | |
| 28 | + # the point of the test is to ensure that the contents appears in | |
| 29 | + # the output file in the correct format. | |
| 30 | + $td->runtest("find desired contents (object-streams=$i)", | |
| 31 | + {$td->COMMAND => | |
| 32 | + "grep -f digitally-signed-sig-dict-contents.out a.pdf"}, | |
| 33 | + {$td->REGEXP => ".*", | |
| 34 | + $td->EXIT_STATUS => 0}); | |
| 35 | +} | |
| 36 | + | |
| 37 | +$n_tests += 4; | |
| 38 | +foreach my $i (qw(preserve disable)) | |
| 39 | +{ | |
| 40 | + $td->runtest("non sig dict contents text string (object-streams=$i)", | |
| 41 | + {$td->COMMAND => | |
| 42 | + "qpdf --object-streams=$i comment-annotation.pdf a.pdf"}, | |
| 43 | + {$td->STRING => "", | |
| 44 | + $td->EXIT_STATUS => 0}); | |
| 45 | + $td->runtest("find desired contents as non hex (object-streams=$i)", | |
| 46 | + {$td->COMMAND => | |
| 47 | + "grep \"/Contents (Salad)\" a.pdf"}, | |
| 48 | + {$td->REGEXP => ".*", | |
| 49 | + $td->EXIT_STATUS => 0}); | |
| 50 | +} | |
| 51 | + | |
| 52 | +$n_tests += 2; | |
| 53 | + $td->runtest("non sig dict contents text string (object-streams=generate)", | |
| 54 | + {$td->COMMAND => | |
| 55 | + "qpdf --object-streams=generate comment-annotation.pdf a.pdf"}, | |
| 56 | + {$td->STRING => "", | |
| 57 | + $td->EXIT_STATUS => 0}); | |
| 58 | + $td->runtest("plain text not found due to compression (object-streams=generate)", | |
| 59 | + {$td->COMMAND => | |
| 60 | + "grep \"/Contents (Salad)\" a.pdf"}, | |
| 61 | + {$td->REGEXP => ".*", | |
| 62 | + $td->EXIT_STATUS => 1}); | |
| 63 | + | |
| 64 | +$n_tests += 12; | |
| 65 | +foreach my $i (qw(40 128 256)) | |
| 66 | +{ | |
| 67 | + my $x = ""; | |
| 68 | + if ($i < 256) | |
| 69 | + { | |
| 70 | + $x = "--allow-weak-crypto"; | |
| 71 | + } | |
| 72 | + $td->runtest("encrypt $i", | |
| 73 | + {$td->COMMAND => | |
| 74 | + "qpdf $x --encrypt '' o $i --" . | |
| 75 | + " digitally-signed.pdf a.pdf"}, | |
| 76 | + {$td->STRING => "", | |
| 77 | + $td->EXIT_STATUS => 0}); | |
| 78 | + $td->runtest("find desired contents (encrypt $i)", | |
| 79 | + {$td->COMMAND => | |
| 80 | + "grep -f digitally-signed-sig-dict-contents.out a.pdf"}, | |
| 81 | + {$td->REGEXP => ".*", | |
| 82 | + $td->EXIT_STATUS => 0}); | |
| 83 | + $td->runtest("decrypt", | |
| 84 | + {$td->COMMAND => | |
| 85 | + "qpdf --decrypt a.pdf b.pdf"}, | |
| 86 | + {$td->REGEXP => ".*", | |
| 87 | + $td->EXIT_STATUS => 0}); | |
| 88 | + $td->runtest("find desired contents (decrypt $i)", | |
| 89 | + {$td->COMMAND => | |
| 90 | + "grep -f digitally-signed-sig-dict-contents.out b.pdf"}, | |
| 91 | + {$td->REGEXP => ".*", | |
| 92 | + $td->EXIT_STATUS => 0}); | |
| 93 | +} | |
| 94 | + | |
| 95 | +$n_tests += 15; | |
| 96 | +foreach my $i (qw(40 128 256)) | |
| 97 | +{ | |
| 98 | + my $x = ""; | |
| 99 | + if ($i < 256) | |
| 100 | + { | |
| 101 | + $x = "--allow-weak-crypto"; | |
| 102 | + } | |
| 103 | + $td->runtest("non sig dict encrypt $i", | |
| 104 | + {$td->COMMAND => | |
| 105 | + "qpdf $x --encrypt '' o $i --" . | |
| 106 | + " comment-annotation.pdf a.pdf"}, | |
| 107 | + {$td->STRING => "", | |
| 108 | + $td->EXIT_STATUS => 0}); | |
| 109 | + $td->runtest("plain text not found due to encryption (non sig dict encrypt $i)", | |
| 110 | + {$td->COMMAND => | |
| 111 | + "grep \"/Contents (Salad)\" a.pdf"}, | |
| 112 | + {$td->REGEXP => ".*", | |
| 113 | + $td->EXIT_STATUS => 1}); | |
| 114 | + $td->runtest("find encrypted contents (non sig dict encrypt $i)", | |
| 115 | + {$td->COMMAND => | |
| 116 | + "grep \"/Contents <.*>\" a.pdf"}, | |
| 117 | + {$td->REGEXP => ".*", | |
| 118 | + $td->EXIT_STATUS => 0}); | |
| 119 | + $td->runtest("non sig dict decrypt", | |
| 120 | + {$td->COMMAND => | |
| 121 | + "qpdf --decrypt a.pdf b.pdf"}, | |
| 122 | + {$td->REGEXP => ".*", | |
| 123 | + $td->EXIT_STATUS => 0}); | |
| 124 | + $td->runtest("find desired contents (non sig dict decrypt $i)", | |
| 125 | + {$td->COMMAND => | |
| 126 | + "grep \"/Contents (Salad)\" b.pdf"}, | |
| 127 | + {$td->REGEXP => ".*", | |
| 128 | + $td->EXIT_STATUS => 0}); | |
| 129 | +} | |
| 130 | + | |
| 131 | +cleanup(); | |
| 132 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/specialized_filter.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | +use Digest::MD5; | |
| 6 | +use File::Copy; | |
| 7 | + | |
| 8 | +unshift(@INC, '.'); | |
| 9 | +require qpdf_test_helpers; | |
| 10 | + | |
| 11 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 12 | + | |
| 13 | +require TestDriver; | |
| 14 | + | |
| 15 | +cleanup(); | |
| 16 | + | |
| 17 | +my $td = new TestDriver('specialized_filter'); | |
| 18 | + | |
| 19 | +my $n_tests = 3; | |
| 20 | +my $n_compare_pdfs = 1; | |
| 21 | + | |
| 22 | +# The PDF file was submitted on bug #83 on github. All the PNG filters | |
| 23 | +# are exercised. The test suite does not exercise PNG predictors with | |
| 24 | +# LZW because I don't have a way to create such a file, but it's very | |
| 25 | +# likely that it will work since the handling of the PNG filters is | |
| 26 | +# separate from the regular decompression. | |
| 27 | +$td->runtest("decode png-filtering", | |
| 28 | + {$td->COMMAND => "qpdf --static-id" . | |
| 29 | + " --compress-streams=n --decode-level=generalized" . | |
| 30 | + " png-filters.pdf a.pdf"}, | |
| 31 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 32 | +$td->runtest("check output", | |
| 33 | + {$td->FILE => "a.pdf"}, | |
| 34 | + {$td->FILE => "png-filters-decoded.pdf"}); | |
| 35 | +compare_pdfs($td, "png-filters.pdf", "a.pdf"); | |
| 36 | + | |
| 37 | +$td->runtest("stream with tiff predictor", | |
| 38 | + {$td->COMMAND => "qpdf --check tiff-predictor.pdf"}, | |
| 39 | + {$td->FILE => "tiff-predictor.out", | |
| 40 | + $td->EXIT_STATUS => 0}, | |
| 41 | + $td->NORMALIZE_NEWLINES); | |
| 42 | + | |
| 43 | +cleanup(); | |
| 44 | +$td->report(calc_ntests($n_tests, $n_compare_pdfs)); | ... | ... |
qpdf/qtest/specific_bugs.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('specific_bugs'); | |
| 16 | + | |
| 17 | +# The number is the github issue number in which the bug was reported. | |
| 18 | +my @bug_tests = ( | |
| 19 | + ["51", "resolve loop", 3], | |
| 20 | + ["99", "object 0", 2], | |
| 21 | + ["99b", "object 0", 2], | |
| 22 | + ["100", "xref reconstruction loop", 2], | |
| 23 | + ["101", "resolve for exception text", 2], | |
| 24 | + ["117", "other infinite loop", 3], | |
| 25 | + ["118", "other infinite loop", 2], | |
| 26 | + ["119", "other infinite loop", 3], | |
| 27 | + ["120", "other infinite loop", 3], | |
| 28 | + ["106", "zlib data error", 3], | |
| 29 | + ["141a", "/W entry size 0", 2], | |
| 30 | + ["141b", "/W entry size 0", 2], | |
| 31 | + ["143", "self-referential ostream", 3, "--preserve-unreferenced"], | |
| 32 | + ["146", "very deeply nested array", 2], | |
| 33 | + ["147", "previously caused memory error", 2], | |
| 34 | + ["148", "free memory on bad flate", 2], | |
| 35 | + ["149", "xref prev pointer loop", 3], | |
| 36 | + ["150", "integer overflow", 2], | |
| 37 | + ["202", "even more deeply nested dictionary", 2], | |
| 38 | + ["263", "empty xref stream", 2], | |
| 39 | + ["335a", "ozz-fuzz-12152", 2], | |
| 40 | + ["335b", "ozz-fuzz-14845", 2], | |
| 41 | + ["fuzz-16214", "stream in object stream", 3, "--preserve-unreferenced"], | |
| 42 | + # When adding to this list, consider adding to CORPUS_FROM_TEST in | |
| 43 | + # fuzz/CMakeLists.txt and updating the count in | |
| 44 | + # fuzz/qtest/fuzz.test. | |
| 45 | + ); | |
| 46 | +my $n_tests = scalar(@bug_tests); | |
| 47 | +foreach my $d (@bug_tests) | |
| 48 | +{ | |
| 49 | + my ($n, $description, $exit_status, $xargs) = @$d; | |
| 50 | + if (! defined $xargs) | |
| 51 | + { | |
| 52 | + $xargs = ""; | |
| 53 | + } | |
| 54 | + if (-f "issue-$n.obfuscated") | |
| 55 | + { | |
| 56 | + # Some of the PDF files in the test suite trigger anti-virus | |
| 57 | + # warnings (MAL/PDFEx-H) and are quarantined or deleted by | |
| 58 | + # some antivirus software. These files are not actually | |
| 59 | + # infected files with malicious intent. They are present in | |
| 60 | + # the test suite to ensure that qpdf does not crash when | |
| 61 | + # process those files. Base64-encode them and pass them to | |
| 62 | + # stdin to prevent anti-virus programs from messing up the | |
| 63 | + # extracted sources. Search for "obfuscated" in test_driver.cc | |
| 64 | + # for instructions on how to obfuscate input files. | |
| 65 | + $td->runtest($description, | |
| 66 | + {$td->COMMAND => "test_driver 45 issue-$n"}, | |
| 67 | + {$td->FILE => "issue-$n.out", | |
| 68 | + $td->EXIT_STATUS => $exit_status}, | |
| 69 | + $td->NORMALIZE_NEWLINES); | |
| 70 | + } | |
| 71 | + else | |
| 72 | + { | |
| 73 | + my $base = (-f "issue-$n.pdf") ? "issue-$n" : "$n"; | |
| 74 | + $td->runtest($description, | |
| 75 | + {$td->COMMAND => "qpdf $xargs $base.pdf a.pdf"}, | |
| 76 | + {$td->FILE => "$base.out", | |
| 77 | + $td->EXIT_STATUS => $exit_status}, | |
| 78 | + $td->NORMALIZE_NEWLINES); | |
| 79 | + } | |
| 80 | +} | |
| 81 | +cleanup(); | |
| 82 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/specific_file.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('specific_file'); | |
| 16 | + | |
| 17 | +my $n_tests = 11; | |
| 18 | + | |
| 19 | +# Special PDF files that caused problems at some point | |
| 20 | + | |
| 21 | +$td->runtest("damaged stream", | |
| 22 | + {$td->COMMAND => "qpdf --check damaged-stream.pdf"}, | |
| 23 | + {$td->FILE => "damaged-stream.out", $td->EXIT_STATUS => 3}, | |
| 24 | + $td->NORMALIZE_NEWLINES); | |
| 25 | +$td->runtest("damaged stream (C)", | |
| 26 | + {$td->COMMAND => "qpdf-ctest 2 damaged-stream.pdf '' a.pdf"}, | |
| 27 | + {$td->FILE => "damaged-stream-c-check.out", $td->EXIT_STATUS => 0}, | |
| 28 | + $td->NORMALIZE_NEWLINES); | |
| 29 | +$td->runtest("compress objstm and xref", | |
| 30 | + {$td->COMMAND => | |
| 31 | + "qpdf --static-id --stream-data=compress". | |
| 32 | + " --object-streams=generate minimal.pdf a.pdf"}, | |
| 33 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 34 | + $td->NORMALIZE_NEWLINES); | |
| 35 | +$td->runtest("check output", | |
| 36 | + {$td->FILE => "a.pdf"}, | |
| 37 | + {$td->FILE => "compress-objstm-xref.pdf"}); | |
| 38 | +$td->runtest("qdf + preserved-unreferenced + xref streams", | |
| 39 | + {$td->COMMAND => "qpdf --qdf --preserve-unreferenced" . | |
| 40 | + " --static-id compress-objstm-xref.pdf a.pdf"}, | |
| 41 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 42 | +$td->runtest("check output", | |
| 43 | + {$td->FILE => "a.pdf"}, | |
| 44 | + {$td->FILE => "compress-objstm-xref-qdf.pdf"}); | |
| 45 | +$td->runtest("check fix-qdf idempotency", | |
| 46 | + {$td->COMMAND => "fix-qdf a.pdf"}, | |
| 47 | + {$td->FILE => "a.pdf", $td->EXIT_STATUS => 0}); | |
| 48 | +$td->runtest("pages points to page", | |
| 49 | + {$td->COMMAND => | |
| 50 | + "qpdf --static-id --linearize pages-is-page.pdf a.pdf"}, | |
| 51 | + {$td->FILE => "pages-is-page.out", $td->EXIT_STATUS => 3}, | |
| 52 | + $td->NORMALIZE_NEWLINES); | |
| 53 | +$td->runtest("check output", | |
| 54 | + {$td->FILE => "a.pdf"}, | |
| 55 | + {$td->FILE => "pages-is-page-out.pdf"}); | |
| 56 | +$td->runtest("Acroform /DR with indirect subkey", | |
| 57 | + {$td->COMMAND => | |
| 58 | + "qpdf --static-id --empty" . | |
| 59 | + " --pages dr-with-indirect-item.pdf -- a.pdf"}, | |
| 60 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 61 | + $td->NORMALIZE_NEWLINES); | |
| 62 | +$td->runtest("check output", | |
| 63 | + {$td->FILE => "a.pdf"}, | |
| 64 | + {$td->FILE => "dr-with-indirect-item-out.pdf"}); | |
| 65 | + | |
| 66 | +cleanup(); | |
| 67 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/split_pages.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | +use Digest::MD5; | |
| 6 | +use File::Copy; | |
| 7 | + | |
| 8 | +unshift(@INC, '.'); | |
| 9 | +require qpdf_test_helpers; | |
| 10 | + | |
| 11 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 12 | + | |
| 13 | +require TestDriver; | |
| 14 | + | |
| 15 | +cleanup(); | |
| 16 | + | |
| 17 | +my $td = new TestDriver('split_pages'); | |
| 18 | + | |
| 19 | +my $n_tests = 42; | |
| 20 | +my $n_compare_pdfs = 2; | |
| 21 | + | |
| 22 | +# sp = split-pages | |
| 23 | +my @sp_cases = ( | |
| 24 | + [11, '%d at beginning', '', '%d_split-out.zdf'], | |
| 25 | + [11, '%d at end', '--qdf', 'split-out.zdf_%d'], | |
| 26 | + [11, '%d in middle', '--allow-weak-crypto --encrypt u o 128 --', | |
| 27 | + 'a-%d-split-out.zdf'], | |
| 28 | + [11, 'pdf extension', '', 'split-out.Pdf'], | |
| 29 | + [4, 'fallback', '--pages 11-pages.pdf 1-3 minimal.pdf --', 'split-out'], | |
| 30 | + [1, 'broken data', '--pages broken-lzw.pdf --', 'split-out.pdf', | |
| 31 | + {$td->FILE => "broken-lzw.out", $td->EXIT_STATUS => 3}], | |
| 32 | + ); | |
| 33 | +for (@sp_cases) | |
| 34 | +{ | |
| 35 | + $n_tests += 1 + $_->[0]; | |
| 36 | +} | |
| 37 | + | |
| 38 | +$td->runtest("split page group > 1", | |
| 39 | + {$td->COMMAND => "qpdf --static-id --split-pages=5 11-pages.pdf" . | |
| 40 | + " --verbose split-out-group.pdf"}, | |
| 41 | + {$td->FILE => "split-pages-group.out", $td->EXIT_STATUS => 0}, | |
| 42 | + $td->NORMALIZE_NEWLINES); | |
| 43 | +foreach my $f ('01-05', '06-10', '11-11') | |
| 44 | +{ | |
| 45 | + $td->runtest("check out group $f", | |
| 46 | + {$td->FILE => "split-out-group-$f.pdf"}, | |
| 47 | + {$td->FILE => "split-exp-group-$f.pdf"}); | |
| 48 | +} | |
| 49 | + | |
| 50 | +$td->runtest("no split-pages to stdout", | |
| 51 | + {$td->COMMAND => "qpdf --split-pages 11-pages.pdf -"}, | |
| 52 | + {$td->FILE => "split-pages-stdout.out", $td->EXIT_STATUS => 2}, | |
| 53 | + $td->NORMALIZE_NEWLINES); | |
| 54 | + | |
| 55 | +$td->runtest("split page with shared resources", | |
| 56 | + {$td->COMMAND => "qpdf --qdf --static-id --split-pages=4". | |
| 57 | + " shared-images.pdf split-out-shared.pdf"}, | |
| 58 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 59 | +foreach my $i (qw(01-04 05-08 09-10)) | |
| 60 | +{ | |
| 61 | + $td->runtest("check output ($i)", | |
| 62 | + {$td->FILE => "split-out-shared-$i.pdf"}, | |
| 63 | + {$td->FILE => "shared-split-$i.pdf"}); | |
| 64 | +} | |
| 65 | + | |
| 66 | +$td->runtest("split page with labels", | |
| 67 | + {$td->COMMAND => "qpdf --qdf --static-id --split-pages=6". | |
| 68 | + " 11-pages-with-labels.pdf split-out-labels.pdf"}, | |
| 69 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 70 | +foreach my $i (qw(01-06 07-11)) | |
| 71 | +{ | |
| 72 | + $td->runtest("check output ($i)", | |
| 73 | + {$td->FILE => "split-out-labels-$i.pdf"}, | |
| 74 | + {$td->FILE => "labels-split-$i.pdf"}); | |
| 75 | +} | |
| 76 | + | |
| 77 | +# See comments in TODO about these expected failures. Search for | |
| 78 | +# "split page with outlines". | |
| 79 | +$td->runtest("split page with outlines", | |
| 80 | + {$td->COMMAND => "qpdf --qdf --static-id --split-pages=10". | |
| 81 | + " outlines-with-actions.pdf split-out-outlines.pdf"}, | |
| 82 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 83 | +foreach my $i (qw(01-10 11-20 21-30)) | |
| 84 | +{ | |
| 85 | + $td->runtest("check output ($i)", | |
| 86 | + {$td->FILE => "split-out-outlines-$i.pdf"}, | |
| 87 | + {$td->FILE => "outlines-split-$i.pdf"}, | |
| 88 | + $td->EXPECT_FAILURE) | |
| 89 | +} | |
| 90 | + | |
| 91 | +foreach my $d (@sp_cases) | |
| 92 | +{ | |
| 93 | + my ($n, $description, $xargs, $out, $exp) = @$d; | |
| 94 | + if (! defined $exp) | |
| 95 | + { | |
| 96 | + $exp = {$td->STRING => "", $td->EXIT_STATUS => 0}; | |
| 97 | + } | |
| 98 | + $td->runtest("split pages " . $description, | |
| 99 | + {$td->COMMAND => | |
| 100 | + "qpdf --static-id --split-pages 11-pages.pdf" . | |
| 101 | + " $xargs $out"}, | |
| 102 | + $exp, | |
| 103 | + $td->NORMALIZE_NEWLINES); | |
| 104 | + my $pattern = $out; | |
| 105 | + my $nlen = length($n); | |
| 106 | + if ($pattern =~ m/\%d/) | |
| 107 | + { | |
| 108 | + $pattern =~ s/\%d/\%0${nlen}d/; | |
| 109 | + } | |
| 110 | + elsif ($pattern =~ m/\.pdf$/i) | |
| 111 | + { | |
| 112 | + $pattern =~ s/(\.pdf$)/-%0${nlen}d$1/i; | |
| 113 | + } | |
| 114 | + else | |
| 115 | + { | |
| 116 | + $pattern .= "-%0${nlen}d"; | |
| 117 | + } | |
| 118 | + for (my $i = 1; $i <= $n; ++$i) | |
| 119 | + { | |
| 120 | + my $actual = sprintf($pattern, $i); | |
| 121 | + my $expected = $actual; | |
| 122 | + $expected =~ s/split-out/split-exp/; | |
| 123 | + $td->runtest("check output page $i ($description)", | |
| 124 | + {$td->FILE => $actual}, | |
| 125 | + {$td->FILE => $expected}); | |
| 126 | + } | |
| 127 | +} | |
| 128 | + | |
| 129 | +$td->runtest("split shared font, xobject", | |
| 130 | + {$td->COMMAND => | |
| 131 | + "qpdf --static-id --qdf --no-original-object-ids" . | |
| 132 | + " --split-pages shared-font-xobject.pdf" . | |
| 133 | + " split-out-shared-font-xobject.pdf"}, | |
| 134 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 135 | +foreach my $i (qw(1 2 3 4)) | |
| 136 | +{ | |
| 137 | + $td->runtest("check output ($i)", | |
| 138 | + {$td->FILE => "split-out-shared-font-xobject-$i.pdf"}, | |
| 139 | + {$td->FILE => "shared-font-xobject-split-$i.pdf"}); | |
| 140 | +} | |
| 141 | + | |
| 142 | +$td->runtest("unreferenced resources with bad token", | |
| 143 | + {$td->COMMAND => | |
| 144 | + "qpdf --qdf --static-id --split-pages=2" . | |
| 145 | + " --remove-unreferenced-resources=yes" . | |
| 146 | + " split-tokens.pdf split-out-bad-token.pdf"}, | |
| 147 | + {$td->FILE => "split-tokens-split.out", $td->EXIT_STATUS => 3}, | |
| 148 | + $td->NORMALIZE_NEWLINES); | |
| 149 | +$td->runtest("check output", | |
| 150 | + {$td->FILE => "split-out-bad-token-1-2.pdf"}, | |
| 151 | + {$td->FILE => "split-tokens-split-1-2.pdf"}); | |
| 152 | +$td->runtest("--no-warn with proxied warnings during split", | |
| 153 | + {$td->COMMAND => | |
| 154 | + "qpdf --qdf --static-id --split-pages=2" . | |
| 155 | + " --no-warn --remove-unreferenced-resources=yes" . | |
| 156 | + " split-tokens.pdf split-out-bad-token.pdf"}, | |
| 157 | + {$td->STRING => "", $td->EXIT_STATUS => 3}, | |
| 158 | + $td->NORMALIZE_NEWLINES); | |
| 159 | + | |
| 160 | +$td->runtest("shared images in form xobject", | |
| 161 | + {$td->COMMAND => "qpdf --qdf --static-id --split-pages". | |
| 162 | + " shared-form-images.pdf split-out-shared-form.pdf"}, | |
| 163 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 164 | +foreach my $i (qw(1 2 3 4 5 6)) | |
| 165 | +{ | |
| 166 | + $td->runtest("check output ($i)", | |
| 167 | + {$td->FILE => "split-out-shared-form-$i.pdf"}, | |
| 168 | + {$td->FILE => "shared-form-split-$i.pdf"}); | |
| 169 | +} | |
| 170 | +$td->runtest("merge for compare", | |
| 171 | + {$td->COMMAND => "qpdf --static-id --empty --pages" . | |
| 172 | + " split-out-shared-form*.pdf -- a.pdf"}, | |
| 173 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 174 | +$td->runtest("check output", | |
| 175 | + {$td->FILE => "a.pdf"}, | |
| 176 | + {$td->FILE => "shared-form-images-merged.pdf"}); | |
| 177 | +compare_pdfs($td, "shared-form-images.pdf", "a.pdf"); | |
| 178 | + | |
| 179 | +$td->runtest("shared form xobject subkey", | |
| 180 | + {$td->COMMAND => "qpdf --qdf --static-id --split-pages". | |
| 181 | + " shared-form-images-xobject.pdf" . | |
| 182 | + " split-out-shared-form-xobject.pdf"}, | |
| 183 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 184 | +foreach my $i (qw(1 2)) | |
| 185 | +{ | |
| 186 | + $td->runtest("check output ($i)", | |
| 187 | + {$td->FILE => "split-out-shared-form-xobject-$i.pdf"}, | |
| 188 | + {$td->FILE => "shared-form-xobject-split-$i.pdf"}); | |
| 189 | +} | |
| 190 | + | |
| 191 | +my @fo_resources = (['form-xobjects-no-resources', 1], | |
| 192 | + ['form-xobjects-some-resources1', 0], | |
| 193 | + ['form-xobjects-some-resources2', 0]); | |
| 194 | +foreach my $d (@fo_resources) | |
| 195 | +{ | |
| 196 | + my ($f, $compare) = @$d; | |
| 197 | + $td->runtest("split $f", | |
| 198 | + {$td->COMMAND => | |
| 199 | + "qpdf --empty --static-id --pages $f.pdf 1 --" . | |
| 200 | + " --remove-unreferenced-resources=yes a.pdf"}, | |
| 201 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 202 | + $td->NORMALIZE_NEWLINES); | |
| 203 | + $td->runtest("check output ($f)", | |
| 204 | + {$td->FILE => "a.pdf"}, | |
| 205 | + {$td->FILE => "$f-out.pdf"}); | |
| 206 | + if ($compare) | |
| 207 | + { | |
| 208 | + compare_pdfs($td, "$f.pdf", "a.pdf"); | |
| 209 | + } | |
| 210 | +} | |
| 211 | + | |
| 212 | +cleanup(); | |
| 213 | +$td->report(calc_ntests($n_tests, $n_compare_pdfs)); | ... | ... |
qpdf/qtest/stream_data.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('stream_data'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("get stream data", | |
| 20 | + {$td->COMMAND => "test_driver 11 stream-data.pdf"}, | |
| 21 | + {$td->FILE => "test11.out", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("get stream data fails on jpeg", | |
| 24 | + {$td->COMMAND => "test_driver 68 jpeg-qstream.pdf"}, | |
| 25 | + {$td->FILE => "test68.out", $td->EXIT_STATUS => 0}, | |
| 26 | + $td->NORMALIZE_NEWLINES); | |
| 27 | + | |
| 28 | +cleanup(); | |
| 29 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/stream_line_terminators.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('stream_line_terminators'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("odd terminators for stream keyword", | |
| 20 | + {$td->COMMAND => | |
| 21 | + "qpdf --qdf --static-id" . | |
| 22 | + " stream-line-enders.pdf a.qdf"}, | |
| 23 | + {$td->FILE => "stream-line-enders.out", | |
| 24 | + $td->EXIT_STATUS => 3}, | |
| 25 | + $td->NORMALIZE_NEWLINES); | |
| 26 | +$td->runtest("check output", | |
| 27 | + {$td->FILE => "a.qdf"}, | |
| 28 | + {$td->FILE => "stream-line-enders.qdf"}); | |
| 29 | + | |
| 30 | +cleanup(); | |
| 31 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/stream_replacements.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('stream_replacements'); | |
| 16 | + | |
| 17 | +my $n_tests = 10; | |
| 18 | + | |
| 19 | +$td->runtest("replace stream data", | |
| 20 | + {$td->COMMAND => "test_driver 7 qstream.pdf"}, | |
| 21 | + {$td->STRING => "test 7 done\n", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("check output", | |
| 24 | + {$td->FILE => "a.pdf"}, | |
| 25 | + {$td->FILE => "replaced-stream-data.pdf"}); | |
| 26 | +$td->runtest("replace stream data compressed", | |
| 27 | + {$td->COMMAND => "test_driver 8 qstream.pdf"}, | |
| 28 | + {$td->FILE => "test8.out", $td->EXIT_STATUS => 0}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | +$td->runtest("check output", | |
| 31 | + {$td->FILE => "a.pdf"}, | |
| 32 | + {$td->FILE => "replaced-stream-data-flate.pdf"}); | |
| 33 | +$td->runtest("new streams", | |
| 34 | + {$td->COMMAND => "test_driver 9 minimal.pdf"}, | |
| 35 | + {$td->FILE => "test9.out", $td->EXIT_STATUS => 0}, | |
| 36 | + $td->NORMALIZE_NEWLINES); | |
| 37 | +$td->runtest("new stream", | |
| 38 | + {$td->FILE => "a.pdf"}, | |
| 39 | + {$td->FILE => "new-streams.pdf"}); | |
| 40 | +$td->runtest("add page contents", | |
| 41 | + {$td->COMMAND => "test_driver 10 minimal.pdf"}, | |
| 42 | + {$td->STRING => "test 10 done\n", $td->EXIT_STATUS => 0}, | |
| 43 | + $td->NORMALIZE_NEWLINES); | |
| 44 | +$td->runtest("new stream", | |
| 45 | + {$td->FILE => "a.pdf"}, | |
| 46 | + {$td->FILE => "add-contents.pdf"}); | |
| 47 | +$td->runtest("functional replace stream data", | |
| 48 | + {$td->COMMAND => "test_driver 78 minimal.pdf"}, | |
| 49 | + {$td->FILE => "test78.out", $td->EXIT_STATUS => 0}, | |
| 50 | + $td->NORMALIZE_NEWLINES); | |
| 51 | +$td->runtest("check output", | |
| 52 | + {$td->FILE => "a.pdf"}, | |
| 53 | + {$td->FILE => "test78.pdf"}); | |
| 54 | + | |
| 55 | +cleanup(); | |
| 56 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/swap_and_replace.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('swap_and_replace'); | |
| 16 | + | |
| 17 | +my $n_tests = 3; | |
| 18 | + | |
| 19 | +$td->runtest("swap and replace", | |
| 20 | + {$td->COMMAND => "test_driver 14 test14-in.pdf"}, | |
| 21 | + {$td->FILE => "test14.out", | |
| 22 | + $td->EXIT_STATUS => 0}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | +$td->runtest("check output", | |
| 25 | + {$td->FILE => "a.pdf"}, | |
| 26 | + {$td->FILE => "test14-out.pdf"}); | |
| 27 | + | |
| 28 | +# Most of the test suite uses static or deterministic ID. This test | |
| 29 | +# case exercises regular ID generation. Test 14 also exercises writing | |
| 30 | +# to memory without static ID. | |
| 31 | +$td->runtest("check non-static ID version", | |
| 32 | + {$td->COMMAND => "sh ./diff-ignore-ID-version a.pdf b.pdf"}, | |
| 33 | + {$td->STRING => "okay\n", $td->EXIT_STATUS => 0}, | |
| 34 | + $td->NORMALIZE_NEWLINES); | |
| 35 | + | |
| 36 | +cleanup(); | |
| 37 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/token_filters.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('token_filters'); | |
| 16 | + | |
| 17 | +my $n_tests = 2; | |
| 18 | + | |
| 19 | +$td->runtest("token filter", | |
| 20 | + {$td->COMMAND => "test_driver 41 coalesce.pdf"}, | |
| 21 | + {$td->STRING => "test 41 done\n", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("check output", | |
| 24 | + {$td->FILE => "a.pdf"}, | |
| 25 | + {$td->FILE => "token-filters-out.pdf"}); | |
| 26 | + | |
| 27 | +cleanup(); | |
| 28 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/tokenizer.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('tokenizer'); | |
| 16 | + | |
| 17 | +my $n_tests = 4; | |
| 18 | + | |
| 19 | +$td->runtest("tokenizer with no ignorable", | |
| 20 | + {$td->COMMAND => "test_tokenizer -no-ignorable tokens.pdf"}, | |
| 21 | + {$td->FILE => "tokens-no-ignorable.out", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | + | |
| 24 | +$td->runtest("tokenizer", | |
| 25 | + {$td->COMMAND => "test_tokenizer tokens.pdf"}, | |
| 26 | + {$td->FILE => "tokens.out", $td->EXIT_STATUS => 0}, | |
| 27 | + $td->NORMALIZE_NEWLINES); | |
| 28 | + | |
| 29 | +$td->runtest("tokenizer with max_len", | |
| 30 | + {$td->COMMAND => "test_tokenizer -maxlen 50 tokens.pdf"}, | |
| 31 | + {$td->FILE => "tokens-maxlen.out", $td->EXIT_STATUS => 0}, | |
| 32 | + $td->NORMALIZE_NEWLINES); | |
| 33 | + | |
| 34 | +$td->runtest("ignore bad token", | |
| 35 | + {$td->COMMAND => | |
| 36 | + "qpdf --show-xref bad-token-startxref.pdf"}, | |
| 37 | + {$td->FILE => "bad-token-startxref.out", | |
| 38 | + $td->EXIT_STATUS => 0}, | |
| 39 | + $td->NORMALIZE_NEWLINES); | |
| 40 | + | |
| 41 | +cleanup(); | |
| 42 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/type_checks.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('type_checks'); | |
| 16 | + | |
| 17 | +my $n_tests = 5; | |
| 18 | + | |
| 19 | +# Whenever object-types.pdf is edited, object-types-os.pdf should be | |
| 20 | +# regenerated. | |
| 21 | +$td->runtest("ensure object-types-os is up-to-date", | |
| 22 | + {$td->COMMAND => | |
| 23 | + "qpdf" . | |
| 24 | + " --object-streams=generate" . | |
| 25 | + " --deterministic-id" . | |
| 26 | + " --stream-data=uncompress" . | |
| 27 | + " object-types.pdf a.pdf"}, | |
| 28 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 29 | +$td->runtest("check file", | |
| 30 | + {$td->FILE => "a.pdf"}, | |
| 31 | + {$td->FILE => "object-types-os.pdf"}); | |
| 32 | +$td->runtest("type checks", | |
| 33 | + {$td->COMMAND => "test_driver 42 object-types.pdf"}, | |
| 34 | + {$td->FILE => "object-types.out", | |
| 35 | + $td->EXIT_STATUS => 0}, | |
| 36 | + $td->NORMALIZE_NEWLINES); | |
| 37 | +$td->runtest("type checks with object streams", | |
| 38 | + {$td->COMMAND => "test_driver 42 object-types-os.pdf"}, | |
| 39 | + {$td->FILE => "object-types-os.out", | |
| 40 | + $td->EXIT_STATUS => 0}, | |
| 41 | + $td->NORMALIZE_NEWLINES); | |
| 42 | +$td->runtest("compound type checks", | |
| 43 | + {$td->COMMAND => "test_driver 82 object-types-os.pdf"}, | |
| 44 | + {$td->STRING => "test 82 done\n", $td->EXIT_STATUS => 0}, | |
| 45 | + $td->NORMALIZE_NEWLINES); | |
| 46 | + | |
| 47 | +cleanup(); | |
| 48 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/unicode_filenames.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('unicode_filenames'); | |
| 16 | + | |
| 17 | +my $n_tests = 3; | |
| 18 | + | |
| 19 | +$td->runtest("create unicode filenames", | |
| 20 | + {$td->COMMAND => "test_unicode_filenames"}, | |
| 21 | + {$td->STRING => "created Unicode filenames\n", | |
| 22 | + $td->EXIT_STATUS => 0}, | |
| 23 | + $td->NORMALIZE_NEWLINES); | |
| 24 | + | |
| 25 | +foreach my $d (['auto-รผ', 1], ['auto-รถฯ', 2]) | |
| 26 | +{ | |
| 27 | + my ($u, $n) = @$d; | |
| 28 | + $td->runtest("unicode filename $u", | |
| 29 | + {$td->COMMAND => "qpdf --check $u.pdf"}, | |
| 30 | + {$td->FILE => "check-unicode-filename-$n.out", | |
| 31 | + $td->EXIT_STATUS => 0}, | |
| 32 | + $td->NORMALIZE_NEWLINES); | |
| 33 | +} | |
| 34 | + | |
| 35 | +cleanup(); | |
| 36 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/unicode_password.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('unicode_password'); | |
| 16 | + | |
| 17 | +my $n_tests = 0; | |
| 18 | +# $n_tests incremented below | |
| 19 | + | |
| 20 | +# Files with each of these passwords when properly encoded have been | |
| 21 | +# tested manually with multiple PDF viewers. Adobe Reader, chrome, | |
| 22 | +# xpdf, and gv can open all of them except R3 with "single-byte", | |
| 23 | +# which can be opened by xpdf and gv but not the others. As of | |
| 24 | +# 2019-01-19, okular and atril (evince) are not able to open R=6 files | |
| 25 | +# with Unicode passwords as generated by qpdf but can open the R=3 | |
| 26 | +# files. | |
| 27 | + | |
| 28 | +# [bits, password-or-password-name, write-encoding, actual-encoding, xargs, | |
| 29 | +# [[read-encoding, strict?, fail?, tried-others, xargs]]] | |
| 30 | +my @unicode_pw_cases = ( | |
| 31 | + [128, 'simple', 'pdf-doc', 'pdf-doc', '', | |
| 32 | + [['utf8', 0, 0, 1, ''], | |
| 33 | + ['utf8', 1, 1, 0, ''], | |
| 34 | + ['pdf-doc', 1, 0, 0, ''], | |
| 35 | + ]], | |
| 36 | + [128, 'simple', 'utf8', 'utf8', '--password-mode=bytes', | |
| 37 | + [['pdf-doc', 0, 0, 1, ''], | |
| 38 | + ['pdf-doc', 1, 1, 0, ''], | |
| 39 | + ['utf8', 1, 0, 0, ''], | |
| 40 | + ]], | |
| 41 | + [128, 'simple', 'utf8', 'pdf-doc', '--password-mode=unicode', | |
| 42 | + [['pdf-doc', 1, 0, 0, ''], | |
| 43 | + ]], | |
| 44 | + [128, 'simple', 'utf8', 'pdf-doc', '--password-mode=auto', | |
| 45 | + [['pdf-doc', 1, 0, 0, ''], | |
| 46 | + ]], | |
| 47 | + [128, 'single-byte', 'utf8', 'pdf-doc', '', | |
| 48 | + [['pdf-doc', 1, 0, 0, ''], | |
| 49 | + ['win-ansi', 0, 0, 1, ''], | |
| 50 | + ]], | |
| 51 | + [128, 'single-byte', 'utf8', 'pdf-doc', '--password-mode=unicode', | |
| 52 | + [['pdf-doc', 1, 0, 0, ''], | |
| 53 | + ['win-ansi', 0, 0, 1, ''], | |
| 54 | + ]], | |
| 55 | + [128, 'single-byte', 'win-ansi', '', '--password-mode=unicode', | |
| 56 | + "supplied password is not valid UTF-8\n", | |
| 57 | + ], | |
| 58 | + [128, 'single-byte', 'win-ansi', 'win-ansi', '', | |
| 59 | + [['win-ansi', 1, 0, 0, ''], | |
| 60 | + ]], | |
| 61 | + [128, 'single-byte', 'pdf-doc', 'pdf-doc', '', | |
| 62 | + [['pdf-doc', 1, 0, 0, ''], | |
| 63 | + ['win-ansi', 0, 0, 1, ''], | |
| 64 | + ['pdf-doc-hex', 1, 0, 0, '--password-mode=hex-bytes'], | |
| 65 | + ]], | |
| 66 | + [128, 'complex', 'utf8', '', '--password-mode=unicode', | |
| 67 | + "supplied password cannot be encoded for 40-bit or" . | |
| 68 | + " 128-bit encryption formats\n" | |
| 69 | + ], | |
| 70 | + [128, 'complex', 'utf8', 'utf8', '--password-mode=bytes', | |
| 71 | + [['utf8', 1, 0, 0, ''], | |
| 72 | + ]], | |
| 73 | + [256, 'single-byte', 'win-ansi', '', '--password-mode=unicode', | |
| 74 | + "supplied password is not valid UTF-8\n", | |
| 75 | + ], | |
| 76 | + [256, 'single-byte', 'win-ansi', '', '--password-mode=auto', | |
| 77 | + "supplied password is not a valid Unicode password, which is" . | |
| 78 | + " required for 256-bit encryption; to really use this password," . | |
| 79 | + " rerun with the --password-mode=bytes option\n", | |
| 80 | + ], | |
| 81 | + [256, 'single-byte', 'win-ansi', 'win-ansi', '--password-mode=bytes', | |
| 82 | + [['utf8', 0, 0, 1, ''], | |
| 83 | + ['utf8', 1, 1, 0, ''], | |
| 84 | + ['win-ansi', 1, 0, 0, ''], | |
| 85 | + ['win-ansi', 0, 0, 0, ''], | |
| 86 | + ['pdf-doc', 0, 0, 1, ''], | |
| 87 | + ['pdf-doc-hex', 0, 0, 1, '--password-mode=hex-bytes'], | |
| 88 | + ]], | |
| 89 | + [256, 'complex', 'utf8', 'utf8', '', | |
| 90 | + [['utf8', 1, 0, 0, ''], | |
| 91 | + ['utf8-hex', 1, 0, 0, '--password-mode=hex-bytes'], | |
| 92 | + ]], | |
| 93 | + [256, 'complex', 'utf8-hex', 'utf8', '--password-mode=hex-bytes', | |
| 94 | + [['utf8', 1, 0, 0, ''], | |
| 95 | + ['utf8-hex', 1, 0, 0, '--password-mode=hex-bytes'], | |
| 96 | + ]], | |
| 97 | + [256, 'complex', 'utf8', 'utf8', '--password-mode=unicode', | |
| 98 | + [['utf8', 1, 0, 0, ''], | |
| 99 | + ['password-arg-simple-utf8', 0, 1, 1, ''], | |
| 100 | + ]], | |
| 101 | + ); | |
| 102 | + | |
| 103 | +for my $d (@unicode_pw_cases) | |
| 104 | +{ | |
| 105 | + my $decode_cases = $d->[5]; | |
| 106 | + $n_tests += 1; | |
| 107 | + if (ref($decode_cases) eq 'ARRAY') | |
| 108 | + { | |
| 109 | + $n_tests += scalar(@$decode_cases); | |
| 110 | + } | |
| 111 | +} | |
| 112 | + | |
| 113 | +foreach my $d (@unicode_pw_cases) | |
| 114 | +{ | |
| 115 | + my ($bits, $pw, $w_encoding, $a_encoding, $xargs, $decode_cases) = @$d; | |
| 116 | + my $w_pfile = "password-bare-$pw-$w_encoding"; | |
| 117 | + my $upass; | |
| 118 | + if (-f $w_pfile) | |
| 119 | + { | |
| 120 | + $upass = '@' . $w_pfile; | |
| 121 | + } | |
| 122 | + else | |
| 123 | + { | |
| 124 | + $upass = "$pw"; | |
| 125 | + } | |
| 126 | + my $outbase = "unicode-pw-$bits-$pw-$w_encoding-$xargs"; | |
| 127 | + my $exp = ''; | |
| 128 | + if (ref($decode_cases) ne 'ARRAY') | |
| 129 | + { | |
| 130 | + $exp = "qpdf: $decode_cases"; | |
| 131 | + $decode_cases = []; | |
| 132 | + } | |
| 133 | + $td->runtest("encode $bits, $pw, $w_encoding", | |
| 134 | + {$td->COMMAND => | |
| 135 | + "qpdf $xargs --static-id --static-aes-iv" . | |
| 136 | + " --allow-weak-crypto" . | |
| 137 | + " --encrypt $upass o $bits -- minimal.pdf a.pdf"}, | |
| 138 | + {$td->STRING => $exp, $td->EXIT_STATUS => ($exp ? 2 : 0)}, | |
| 139 | + $td->NORMALIZE_NEWLINES); | |
| 140 | + foreach my $d2 (@$decode_cases) | |
| 141 | + { | |
| 142 | + my ($r_encoding, $strict, $xfail, $tried_others, $r_xargs) = @$d2; | |
| 143 | + my $r_pfile = "password-arg-$pw-$r_encoding"; | |
| 144 | + if (! -f $r_pfile) | |
| 145 | + { | |
| 146 | + $r_pfile = $r_encoding; | |
| 147 | + } | |
| 148 | + my $r_output = ""; | |
| 149 | + $r_output .= "trying other\n" if $tried_others; | |
| 150 | + if ($xfail) | |
| 151 | + { | |
| 152 | + $r_output .= "qpdf: a.pdf: invalid password\n"; | |
| 153 | + } | |
| 154 | + else | |
| 155 | + { | |
| 156 | + $r_output .= "R = " . ($bits == 128 ? '3' : '6') . "\n"; | |
| 157 | + open(F, "<password-bare-$pw-$a_encoding") or die; | |
| 158 | + chomp (my $apw = <F>); | |
| 159 | + close(F); | |
| 160 | + $r_output .= "User password = $apw\n"; | |
| 161 | + } | |
| 162 | + $r_xargs .= $strict ? ' --suppress-password-recovery' : ''; | |
| 163 | + $td->runtest("decrypt $pw, $r_encoding, strict=$strict", | |
| 164 | + {$td->COMMAND => | |
| 165 | + "qpdf --show-encryption --verbose" . | |
| 166 | + " $r_xargs a.pdf \@$r_pfile", | |
| 167 | + $td->FILTER => "perl show-unicode-encryption.pl"}, | |
| 168 | + {$td->STRING => "$r_output", | |
| 169 | + $td->EXIT_STATUS => ($xfail ? 2 : 0)}, | |
| 170 | + $td->NORMALIZE_NEWLINES); | |
| 171 | + } | |
| 172 | +} | |
| 173 | + | |
| 174 | +$n_tests += 5; | |
| 175 | + | |
| 176 | +$td->runtest("bytes fallback warning", | |
| 177 | + {$td->COMMAND => | |
| 178 | + "qpdf --allow-weak-crypto" . | |
| 179 | + " --encrypt \@password-bare-complex-utf8 o 128 --" . | |
| 180 | + " minimal.pdf a.pdf"}, | |
| 181 | + {$td->FILE => "bytes-fallback.out", $td->EXIT_STATUS => 0}, | |
| 182 | + $td->NORMALIZE_NEWLINES); | |
| 183 | +{ # local scope | |
| 184 | + my $r_output = ""; | |
| 185 | + $r_output .= "R = 3\n"; | |
| 186 | + open(F, "<password-bare-complex-utf8") or die; | |
| 187 | + chomp (my $apw = <F>); | |
| 188 | + close(F); | |
| 189 | + $r_output .= "User password = $apw\n"; | |
| 190 | + $td->runtest("decrypt bytes fallback", | |
| 191 | + {$td->COMMAND => | |
| 192 | + "qpdf --show-encryption --verbose" . | |
| 193 | + " a.pdf \@password-arg-complex-utf8" . | |
| 194 | + " --password-mode=bytes", | |
| 195 | + $td->FILTER => "perl show-unicode-encryption.pl"}, | |
| 196 | + {$td->STRING => "$r_output", $td->EXIT_STATUS => 0}, | |
| 197 | + $td->NORMALIZE_NEWLINES); | |
| 198 | +} | |
| 199 | + | |
| 200 | +# Exercise passing Unicode passwords via the command line. This tests | |
| 201 | +# wmain for Windows and assumes a UTF-8 locale for other platforms. | |
| 202 | +$td->runtest("Unicode at CLI", | |
| 203 | + {$td->COMMAND => | |
| 204 | + "qpdf --encrypt ฯ สฌ 256 --" . | |
| 205 | + " minimal.pdf a.pdf"}, | |
| 206 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 207 | + $td->NORMALIZE_NEWLINES); | |
| 208 | +$td->runtest("Decrypt using user password", | |
| 209 | + {$td->COMMAND => "qpdf --show-encryption a.pdf --password=ฯ"}, | |
| 210 | + {$td->FILE => "unicode-up.out", $td->EXIT_STATUS => 0}, | |
| 211 | + $td->NORMALIZE_NEWLINES); | |
| 212 | +$td->runtest("Decrypt using owner password", | |
| 213 | + {$td->COMMAND => "qpdf --show-encryption a.pdf --password=สฌ"}, | |
| 214 | + {$td->FILE => "unicode-op.out", $td->EXIT_STATUS => 0}, | |
| 215 | + $td->NORMALIZE_NEWLINES); | |
| 216 | + | |
| 217 | +cleanup(); | |
| 218 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/weak_cryptography.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('weak_cryptography_cryptography'); | |
| 16 | + | |
| 17 | +my $n_tests = 4; | |
| 18 | + | |
| 19 | +$td->runtest("256-bit: no warning", | |
| 20 | + {$td->COMMAND => 'qpdf --encrypt "" "" 256 -- minimal.pdf a.pdf'}, | |
| 21 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | +$td->runtest("128-bit with AES: no warning", | |
| 24 | + {$td->COMMAND => 'qpdf --encrypt "" "" 128 --use-aes=y --' . | |
| 25 | + ' minimal.pdf a.pdf'}, | |
| 26 | + {$td->STRING => "", $td->EXIT_STATUS => 0}, | |
| 27 | + $td->NORMALIZE_NEWLINES); | |
| 28 | +$td->runtest("128-bit without AES: error", | |
| 29 | + {$td->COMMAND => 'qpdf --encrypt "" "" 128 -- minimal.pdf a.pdf'}, | |
| 30 | + {$td->REGEXP => "Pass --allow-weak-crypto to enable", | |
| 31 | + $td->EXIT_STATUS => 2}, | |
| 32 | + $td->NORMALIZE_NEWLINES); | |
| 33 | +$td->runtest("40-bit: error", | |
| 34 | + {$td->COMMAND => 'qpdf --encrypt "" "" 40 -- minimal.pdf a.pdf'}, | |
| 35 | + {$td->REGEXP => "Pass --allow-weak-crypto to enable", | |
| 36 | + $td->EXIT_STATUS => 2}, | |
| 37 | + $td->NORMALIZE_NEWLINES); | |
| 38 | + | |
| 39 | +cleanup(); | |
| 40 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/windows_shell_globbing.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('windows_shell_globbing'); | |
| 16 | + | |
| 17 | +my $n_tests = 1; | |
| 18 | + | |
| 19 | +$td->runtest("shell wildcard expansion", | |
| 20 | + {$td->COMMAND => "test_shell_glob 'good*.pdf'"}, | |
| 21 | + {$td->STRING => "PASSED\n", $td->EXIT_STATUS => 0}, | |
| 22 | + $td->NORMALIZE_NEWLINES); | |
| 23 | + | |
| 24 | +cleanup(); | |
| 25 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/writer_version.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('writer_version'); | |
| 16 | + | |
| 17 | +my $n_tests = 7; | |
| 18 | + | |
| 19 | +# Min/Force version | |
| 20 | +$td->runtest("set min version", | |
| 21 | + {$td->COMMAND => "qpdf --verbose --min-version=1.6 good1.pdf a.pdf"}, | |
| 22 | + {$td->STRING => "qpdf: wrote file a.pdf\n", | |
| 23 | + $td->EXIT_STATUS => 0}, | |
| 24 | + $td->NORMALIZE_NEWLINES); | |
| 25 | +$td->runtest("check version", | |
| 26 | + {$td->COMMAND => "qpdf --check a.pdf"}, | |
| 27 | + {$td->FILE => "min-version.out", | |
| 28 | + $td->EXIT_STATUS => 0}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | +$td->runtest("force version", | |
| 31 | + {$td->COMMAND => "qpdf --force-version=1.4 a.pdf b.pdf"}, | |
| 32 | + {$td->STRING => "", | |
| 33 | + $td->EXIT_STATUS => 0}, | |
| 34 | + $td->NORMALIZE_NEWLINES); | |
| 35 | +$td->runtest("check version", | |
| 36 | + {$td->COMMAND => "qpdf --check b.pdf"}, | |
| 37 | + {$td->FILE => "forced-version.out", | |
| 38 | + $td->EXIT_STATUS => 0}, | |
| 39 | + $td->NORMALIZE_NEWLINES); | |
| 40 | +unlink "a.pdf", "b.pdf" or die; | |
| 41 | +$td->runtest("C API: min/force versions", | |
| 42 | + {$td->COMMAND => "qpdf-ctest 14 object-stream.pdf '' a.pdf b.pdf"}, | |
| 43 | + {$td->STRING => "C test 14 done\n", | |
| 44 | + $td->EXIT_STATUS => 0}, | |
| 45 | + $td->NORMALIZE_NEWLINES); | |
| 46 | +$td->runtest("C check version 1", | |
| 47 | + {$td->COMMAND => "qpdf-ctest 1 a.pdf '' ''"}, | |
| 48 | + {$td->FILE => "c-min-version.out", | |
| 49 | + $td->EXIT_STATUS => 0}, | |
| 50 | + $td->NORMALIZE_NEWLINES); | |
| 51 | +$td->runtest("C check version 2", | |
| 52 | + {$td->COMMAND => "qpdf --check b.pdf"}, | |
| 53 | + {$td->FILE => "forced-version.out", | |
| 54 | + $td->EXIT_STATUS => 0}, | |
| 55 | + $td->NORMALIZE_NEWLINES); | |
| 56 | + | |
| 57 | +cleanup(); | |
| 58 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/xref_errors.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('xref_errors'); | |
| 16 | + | |
| 17 | +my $n_tests = 6; | |
| 18 | + | |
| 19 | +# Handle file with invalid xref table and object 0 as a regular object | |
| 20 | +# (bug 3159950). | |
| 21 | +$td->runtest("check obj0.pdf", | |
| 22 | + {$td->COMMAND => "qpdf --check obj0.pdf"}, | |
| 23 | + {$td->FILE => "obj0-check.out", | |
| 24 | + $td->EXIT_STATUS => 3}, | |
| 25 | + $td->NORMALIZE_NEWLINES); | |
| 26 | + | |
| 27 | +# Demonstrate show-xref after check and not after check to illustrate | |
| 28 | +# that it can dump the real xref or the recovered xref. | |
| 29 | +$td->runtest("dump bad xref", | |
| 30 | + {$td->COMMAND => "qpdf --show-xref bad-xref-entry.pdf"}, | |
| 31 | + {$td->FILE => "bad-xref-entry.out", | |
| 32 | + $td->EXIT_STATUS => 0}, | |
| 33 | + $td->NORMALIZE_NEWLINES); | |
| 34 | +# Test @file here too. | |
| 35 | +open(F, ">args") or die; | |
| 36 | +print F "--check\n"; | |
| 37 | +print F "--show-xref\n"; | |
| 38 | +close(F); | |
| 39 | +$td->runtest("dump corrected bad xref", | |
| 40 | + {$td->COMMAND => "qpdf \@args bad-xref-entry.pdf"}, | |
| 41 | + {$td->FILE => "bad-xref-entry-corrected.out", | |
| 42 | + $td->EXIT_STATUS => 3}, | |
| 43 | + $td->NORMALIZE_NEWLINES); | |
| 44 | +unlink "args"; | |
| 45 | + | |
| 46 | +$td->runtest("combine show and --pages", | |
| 47 | + {$td->COMMAND => | |
| 48 | + "qpdf --empty --pages minimal.pdf -- --show-pages"}, | |
| 49 | + {$td->FILE => "show-pages-pages.out", | |
| 50 | + $td->EXIT_STATUS => 0}, | |
| 51 | + $td->NORMALIZE_NEWLINES); | |
| 52 | + | |
| 53 | +$td->runtest("show number of pages", | |
| 54 | + {$td->COMMAND => | |
| 55 | + "qpdf --show-npages 20-pages.pdf --password=user"}, | |
| 56 | + {$td->STRING => "20\n", $td->EXIT_STATUS => 0}, | |
| 57 | + $td->NORMALIZE_NEWLINES); | |
| 58 | + | |
| 59 | +# Issue 482 -- don't range check fields[2] for xref entry type 0. | |
| 60 | +$td->runtest("out of range in deleted object", | |
| 61 | + {$td->COMMAND => "qpdf --check xref-range.pdf"}, | |
| 62 | + {$td->FILE => "xref-range.out", $td->EXIT_STATUS => 0}, | |
| 63 | + $td->NORMALIZE_NEWLINES); | |
| 64 | + | |
| 65 | +cleanup(); | |
| 66 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/xref_streams.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('xref_streams'); | |
| 16 | + | |
| 17 | +my $n_tests = 3; | |
| 18 | + | |
| 19 | +# Handle xref stream with more entries than reported (bug 2872265) | |
| 20 | +$td->runtest("xref with short size", | |
| 21 | + {$td->COMMAND => "qpdf --show-xref xref-with-short-size.pdf"}, | |
| 22 | + {$td->FILE => "xref-with-short-size.out", | |
| 23 | + $td->EXIT_STATUS => 3}, | |
| 24 | + $td->NORMALIZE_NEWLINES); | |
| 25 | +$td->runtest("recover xref with short size", | |
| 26 | + {$td->COMMAND => "qpdf xref-with-short-size.pdf a.pdf"}, | |
| 27 | + {$td->FILE => "xref-with-short-size-recover.out", | |
| 28 | + $td->EXIT_STATUS => 3}, | |
| 29 | + $td->NORMALIZE_NEWLINES); | |
| 30 | +$td->runtest("show new xref stream", | |
| 31 | + {$td->COMMAND => "qpdf --show-xref a.pdf"}, | |
| 32 | + {$td->FILE => "xref-with-short-size-new.out", | |
| 33 | + $td->EXIT_STATUS => 0}, | |
| 34 | + $td->NORMALIZE_NEWLINES); | |
| 35 | + | |
| 36 | +cleanup(); | |
| 37 | +$td->report($n_tests); | ... | ... |