PDF.t 11 KB

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