1# Before "make install", this script should be runnable with "make test". 2# After "make install" it should work as "perl t/PDF.t". 3 4BEGIN { 5 $| = 1; print "1..26\n"; $Image::ExifTool::configFile = ''; 6 require './t/TestLib.pm'; t::TestLib->import(); 7} 8END {print "not ok 1\n" unless $loaded;} 9 10# test 1: Load the module(s) 11use Image::ExifTool 'ImageInfo'; 12use Image::ExifTool::PDF; 13$loaded = 1; 14print "ok 1\n"; 15 16my $testname = 'PDF'; 17my $testnum = 1; 18 19#------------------------------------------------------------------------------ 20# PDF decryption test 21# Inputs: 0) Encrypt object reference, plus additional entries (see below), 22# 1) Test number, 2) encrypt flag (false for decryption) 23# Returns: nothing, but prints test result 24# Additional encrypt hash entries used by this routine: 25# _id - PDF file ID 26# _ref - PDF object reference string 27# _req - other module required for this test 28# _ciphertext - encrypted data 29# _plaintext - expected decryption result 30# _password - password for decryption (if used) 31sub CryptTest($$;$) 32{ 33 my ($cryptInfo, $testNum, $encrypt) = @_; 34 my $skip = ''; 35 if (eval "require $$cryptInfo{_req}") { 36 my $exifTool = new Image::ExifTool; 37 $exifTool->Options('Password', $$cryptInfo{_password}); 38 my $err = Image::ExifTool::PDF::DecryptInit($exifTool, $cryptInfo, $$cryptInfo{_id}); 39 unless ($err) { 40 my $data = $$cryptInfo{$encrypt ? '_plaintext' : '_ciphertext'}; 41 Image::ExifTool::PDF::Crypt(\$data, $$cryptInfo{_ref} || '1 0 R', $encrypt); 42 $err = $$cryptInfo{_error}; 43 if (not $err and $data ne $$cryptInfo{$encrypt ? '_ciphertext' : '_plaintext'}) { 44 $err = "Test $testnum (decryption) returned wrong value:\n " . unpack('H*',$data); 45 } 46 } 47 if ($err) { 48 warn "\n $err\n"; 49 print 'not '; 50 } 51 } else { 52 $skip = " # skip Requires $$cryptInfo{_req}"; 53 } 54 print "ok $testnum$skip\n"; 55} 56 57# test 2: Extract information from PDF.pdf 58{ 59 ++$testnum; 60 my $exifTool = new Image::ExifTool; 61 my $info = $exifTool->ImageInfo('t/images/PDF.pdf'); 62 print 'not ' unless check($exifTool, $info, $testname, $testnum); 63 print "ok $testnum\n"; 64} 65 66# test 3: Test Standard PDF decryption 67{ 68 ++$testnum; 69 my %cryptInfo = ( 70 Filter => '/Standard', 71 P => -60, 72 V => 1, 73 R => 0, 74 O => '<2055c756c72e1ad702608e8196acad447ad32d17cff583235f6dd15fed7dab67>', 75 U => '<7150bd1da9d292af3627fca6a8dde1d696e25312041aed09059f9daee04353ae>', 76 _id => pack('H*','12116a1a124ae4cd8179e8978f6ac88b'), 77 _req => 'Digest::MD5', 78 _ref => '4 0 R', 79 _ciphertext => pack('N', 0x34a290d3), 80 _plaintext => pack('N', 0x5924d335), 81 ); 82 CryptTest(\%cryptInfo, $testNum); 83} 84 85# tests 4-21: Test writing, deleting and reverting two different files 86{ 87 # do a bunch of edits 88 my @edits = ([ # (on file containing both PDF Info and XMP) 89 [ # test 4: write PDF and XMP information 90 [ 'PDF:Creator' => 'me'], 91 [ 'XMP:Creator' => 'you' ], 92 [ 'AllDates' => '2:30', Shift => -1 ], 93 ],[ # test 5: delete all PDF 94 [ 'PDF:all' ], 95 ],[ # test 6: write some XMP 96 [ 'XMP:Author' => 'them' ], 97 ],[ # test 7: create new PDF 98 [ 'PDF:Keywords' => 'one' ], 99 [ 'PDF:Keywords' => 'two' ], 100 [ 'AppleKeywords' => 'three' ], 101 [ 'AppleKeywords' => 'four' ], 102 ],[ # test 8: delete all XMP 103 [ 'XMP:all' ], 104 ],[ # test 9: write some PDF 105 [ 'PDF:Keywords' => 'another one', AddValue => 1 ], 106 [ 'AppleKeywords' => 'three', DelValue => 1 ], 107 ],[ # test 10: create new XMP 108 [ 'XMP:Author' => 'us' ], 109 ],[ # test 11: write some PDF 110 [ 'PDF:Keywords' => 'two', DelValue => 1 ], 111 [ 'AppleKeywords' => 'five', AddValue => 1 ], 112 ],[ # test 12: delete re-added XMP 113 [ 'XMP:all' ], 114 ], 115 ],[ # (on file without PDF Info or XMP) 116 [ # test 14: create new XMP 117 [ 'XMP:Author' => 'him' ], 118 ],[ # test 15: create new PDF 119 [ 'PDF:Author' => 'her' ], 120 ],[ # test 16: delete XMP and PDF 121 [ 'XMP:all' ], 122 [ 'PDF:all' ], 123 ],[ # test 17: delete XMP and PDF again 124 [ 'XMP:all' ], 125 [ 'PDF:all' ], 126 ],[ # test 18: create new PDF 127 [ 'PDF:Author' => 'it' ], 128 ],[ # test 19: create new XMP 129 [ 'XMP:Author' => 'thing' ], 130 ],[ # test 20: delete all 131 [ 'all' ], 132 ], 133 ]); 134 my $testSet; 135 foreach $testSet (0,1) { 136 my ($edit, $testfile2, $lastOK); 137 my $testfile = 't/images/' . ($testSet ? 'PDF2.pdf' : 'PDF.pdf'); 138 my $testfile1 = $testfile; 139 my $exifTool = new Image::ExifTool; 140 $exifTool->Options(PrintConv => 0); 141 foreach $edit (@{$edits[$testSet]}) { 142 ++$testnum; 143 $exifTool->SetNewValue(); 144 $exifTool->SetNewValue(@$_) foreach @$edit; 145 $testfile2 = "t/${testname}_${testnum}_failed.pdf"; 146 unlink $testfile2; 147 $exifTool->WriteInfo($testfile1, $testfile2); 148 my $info = $exifTool->ImageInfo($testfile2, 149 qw{Filesize PDF:all XMP:Creator XMP:Author AllDates}); 150 my $ok = check($exifTool, $info, $testname, $testnum); 151 print 'not ' unless $ok; 152 print "ok $testnum\n"; 153 # erase source file if previous test was OK 154 unlink $testfile1 if $lastOK; 155 $lastOK = $ok; 156 $testfile1 = $testfile2; # use this file for the next test 157 } 158 # revert all edits and compare with original file 159 ++$testnum; 160 $exifTool->SetNewValue('PDF-update:all'); 161 $testfile2 = "t/${testname}_${testnum}_failed.pdf"; 162 unlink $testfile2; 163 $exifTool->WriteInfo($testfile1, $testfile2); 164 if (binaryCompare($testfile2, $testfile)) { 165 unlink $testfile2; 166 } else { 167 print 'not '; 168 } 169 print "ok $testnum\n"; 170 unlink $testfile1 if $lastOK; 171 } 172} 173 174# test 22: Delete all tags 175{ 176 ++$testnum; 177 my $exifTool = new Image::ExifTool; 178 my $testfile = "t/${testname}_${testnum}_failed.pdf"; 179 unlink $testfile; 180 $exifTool->Options(IgnoreMinorErrors => 1); 181 $exifTool->SetNewValue(all => undef); 182 my $ok = writeInfo($exifTool, 't/images/PDF.pdf', $testfile); 183 $exifTool->Options(IgnoreMinorErrors => 0); 184 my $info = $exifTool->ImageInfo($testfile,'pdf:all','xmp:all',{Duplicates=>1,Unknown=>1}); 185 if ($ok and check($exifTool, $info, $testname, $testnum)) { 186 unlink $testfile; 187 } else { 188 print 'not '; 189 } 190 print "ok $testnum\n"; 191} 192 193# test 23: Test AES decryption alone (tests 24-26 require Digest::MD5 or Digest::SHA) 194{ 195 ++$testnum; 196 require Image::ExifTool::AES; 197 my $data = pack('H*','6fdc3ca684348bc8f31379aa46455d7b60c0989e027c1d82e746f136d6e95b7485735793ff64310e5b9e367dcc26f564'); 198 my $err = Image::ExifTool::AES::Crypt(\$data, '11223344556677889900112233445566'); 199 if ($err) { 200 warn "\n $err\n"; 201 print 'not '; 202 } elsif ($data ne 'ExifTool AES Test') { 203 my $hex = unpack 'H*', $data; 204 warn "\n Incorrect result from AES decryption:\n"; 205 warn " $hex\n"; 206 print 'not '; 207 } 208 print "ok $testnum\n"; 209} 210 211# test 24-26: Test AESV2 and AESV3 decryption 212{ 213 my @encrypt = ( 214 # AESV2 without password 215 { 216 Filter => '/Standard', 217 V => 4, 218 R => 4, 219 P => -1340, 220 Length => 128, 221 StmF => '/StdCF', 222 StrF => '/StdCF', 223 CF => { 224 StdCF => { 225 AuthEvent => '/DocOpen', 226 CFM => '/AESV2', 227 Length => 16, 228 }, 229 }, 230 EncryptMetadata => 'false', 231 O => '<181ee8e93a99fa1c2a534dd68a5ab07c54268cfe8fbf28c468316b6f732674c1>', 232 U => '<a3525aef4143f4419c78b109317f0e5200000000000000000000000000000000>', 233 _req => 'Digest::MD5', 234 _ref => '4 0 R', 235 _id => pack('H*','d0a736f05faf64c6b52dea82a2ad53e0'), 236 _plaintext => 'This was a test', 237 _ciphertext => pack('H*', 'a86b5e00d9c7e4455cf5d8cedf195c2060e1467ea6d698876a77e9a66cb7867c'), 238 }, 239 # AESV3 without password 240 { 241 Filter => '/Standard', 242 V => 5, 243 R => 5, 244 P => -1028, 245 Length => 256, 246 StmF => '/StdCF', 247 StrF => '/StdCF', 248 CF => { 249 StdCF => { 250 AuthEvent => '/DocOpen', 251 CFM => '/AESV3', 252 Length => 32, 253 }, 254 }, 255 Perms => '<014ee28fe2b91e2198a593b7c3b22f50>', 256 O => '<83e5edfcdecbe2ebe6d519dbafe80fd453028dda119eb76d0216e1344392320d60e1467ea6d698876a77e9a66cb7867c>', 257 U => '<e5e7ade8aebdc9413a0fd176efc4081bdbad3b16a67ece7a01fadb24010a003ea86b5e00d9c7e4455cf5d8cedf195c20>', 258 OE => '<a29f37f1f085b575d9016daad05ca466dd073ba5d067cc7ffa8ef7d1605e460e>', 259 UE => '<47ea891b25af77aaceccf8f2fdeff0c09e9d0f67275f059dbfabbb18fcbf848d>', 260 _req => 'Digest::SHA', 261 _ref => 'dummy', 262 _id => pack('H*','618cb5be1d82fceea9a501b62d408296'), 263 _plaintext => 'This was a test', 264 _ciphertext => pack('H*', 'e90756e8fd60fb7390c34d931e3e3d61898cd133e613e8cf86cd40f7b207a62d'), 265 }, 266 # AESV3 with a password 267 { 268 Filter => '/Standard', 269 V => 5, 270 R => 5, 271 P => -1028, 272 Length => 256, 273 StmF => '/StdCF', 274 StrF => '/StdCF', 275 CF => { 276 StdCF => { 277 AuthEvent => '/DocOpen', 278 CFM => '/AESV3', 279 Length => 32, 280 }, 281 }, 282 Perms => '<014ee28fe2b91e2198a593b7c3b22f50>', 283 O => '<31eefe924a298d8bf19eafc9be6abdfa65a97478f94e907dccff5ac000b83fa521167b86cf70bf77d4a054bc9a59573d>', 284 U => '<6525a788c2ebf27baa45f526bcdb9d2f96c3c67ae1c62324135cac0b823451ba9ad8edb68d167d2d8370d799c41d17d7>', 285 OE => '<ea58e3c731999cdc0f8a395c7391836c2b2db0b4ac86439b3fe5692ddc71671a>', 286 UE => '<f6818f43e176dfe8912f62717032169cf48854f540f7b7641be363ef50371f07>', 287 _req => 'Digest::SHA', 288 _ref => 'dummy', 289 _id => pack('H*','b5f9d17b07152a45bc0a939727c389ad'), 290 _plaintext => 'This was a test', 291 _password => 'ExifTool', 292 _ciphertext => pack('H*', '8bb3565d8c4b9df8cc350954d9f91a46aa47e40eeb5a0cff559acd5ec3e94244'), 293 }); 294 my $exifTool = new Image::ExifTool; 295 my $cryptInfo; 296 foreach $cryptInfo (@encrypt) { 297 ++$testnum; 298 my $encrypt = 0; # (set to 1 to generate ciphertext strings) 299 CryptTest($cryptInfo, $testNum, $encrypt); 300 } 301} 302 303 304# end 305