Commit f8306913ba6eb751cd7f408d04f2d65d8cd3b341

Authored by Jay Berkenbilt
1 parent 9eb5982f

Update "C" API with functions for new features

ChangeLog
  1 +2012-12-31 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Add new methods qpdf_get_pdf_extension_level,
  4 + qpdf_set_r5_encryption_parameters,
  5 + qpdf_set_r6_encryption_parameters,
  6 + qpdf_set_minimum_pdf_version_and_extension, and
  7 + qpdf_force_pdf_version_and_extension to support new functionality
  8 + from the C API.
  9 +
1 2012-12-30 Jay Berkenbilt <ejb@ql.org> 10 2012-12-30 Jay Berkenbilt <ejb@ql.org>
2 11
3 * Fix long-standing bug that could theoretically have resulted in 12 * Fix long-standing bug that could theoretically have resulted in
include/qpdf/qpdf-c.h
@@ -213,6 +213,10 @@ extern &quot;C&quot; { @@ -213,6 +213,10 @@ extern &quot;C&quot; {
213 QPDF_DLL 213 QPDF_DLL
214 char const* qpdf_get_pdf_version(qpdf_data qpdf); 214 char const* qpdf_get_pdf_version(qpdf_data qpdf);
215 215
  216 + /* Return the extension level of the PDF file. */
  217 + QPDF_DLL
  218 + int qpdf_get_pdf_extension_level(qpdf_data qpdf);
  219 +
216 /* Return the user password. If the file is opened using the 220 /* Return the user password. If the file is opened using the
217 * owner password, the user password may be retrieved using this 221 * owner password, the user password may be retrieved using this
218 * function. If the file is opened using the user password, this 222 * function. If the file is opened using the user password, this
@@ -359,14 +363,36 @@ extern &quot;C&quot; { @@ -359,14 +363,36 @@ extern &quot;C&quot; {
359 QPDF_BOOL encrypt_metadata, QPDF_BOOL use_aes); 363 QPDF_BOOL encrypt_metadata, QPDF_BOOL use_aes);
360 364
361 QPDF_DLL 365 QPDF_DLL
  366 + void qpdf_set_r5_encryption_parameters(
  367 + qpdf_data qpdf, char const* user_password, char const* owner_password,
  368 + QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract,
  369 + enum qpdf_r3_print_e print, enum qpdf_r3_modify_e modify,
  370 + QPDF_BOOL encrypt_metadata);
  371 +
  372 + QPDF_DLL
  373 + void qpdf_set_r6_encryption_parameters(
  374 + qpdf_data qpdf, char const* user_password, char const* owner_password,
  375 + QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract,
  376 + enum qpdf_r3_print_e print, enum qpdf_r3_modify_e modify,
  377 + QPDF_BOOL encrypt_metadata);
  378 +
  379 + QPDF_DLL
362 void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value); 380 void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value);
363 381
364 QPDF_DLL 382 QPDF_DLL
365 void qpdf_set_minimum_pdf_version(qpdf_data qpdf, char const* version); 383 void qpdf_set_minimum_pdf_version(qpdf_data qpdf, char const* version);
366 384
367 QPDF_DLL 385 QPDF_DLL
  386 + void qpdf_set_minimum_pdf_version_and_extension(
  387 + qpdf_data qpdf, char const* version, int extension_level);
  388 +
  389 + QPDF_DLL
368 void qpdf_force_pdf_version(qpdf_data qpdf, char const* version); 390 void qpdf_force_pdf_version(qpdf_data qpdf, char const* version);
369 391
  392 + QPDF_DLL
  393 + void qpdf_force_pdf_version_and_extension(
  394 + qpdf_data qpdf, char const* version, int extension_level);
  395 +
370 /* Do actual write operation. */ 396 /* Do actual write operation. */
371 QPDF_DLL 397 QPDF_DLL
372 QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf); 398 QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf);
libqpdf/qpdf-c.cc
@@ -288,6 +288,12 @@ char const* qpdf_get_pdf_version(qpdf_data qpdf) @@ -288,6 +288,12 @@ char const* qpdf_get_pdf_version(qpdf_data qpdf)
288 return qpdf->tmp_string.c_str(); 288 return qpdf->tmp_string.c_str();
289 } 289 }
290 290
  291 +int qpdf_get_pdf_extension_level(qpdf_data qpdf)
  292 +{
  293 + QTC::TC("qpdf", "qpdf-c called qpdf_get_pdf_extension_level");
  294 + return qpdf->qpdf->getExtensionLevel();
  295 +}
  296 +
291 char const* qpdf_get_user_password(qpdf_data qpdf) 297 char const* qpdf_get_user_password(qpdf_data qpdf)
292 { 298 {
293 QTC::TC("qpdf", "qpdf-c called qpdf_get_user_password"); 299 QTC::TC("qpdf", "qpdf-c called qpdf_get_user_password");
@@ -566,6 +572,32 @@ void qpdf_set_r4_encryption_parameters( @@ -566,6 +572,32 @@ void qpdf_set_r4_encryption_parameters(
566 encrypt_metadata, use_aes); 572 encrypt_metadata, use_aes);
567 } 573 }
568 574
  575 +void qpdf_set_r5_encryption_parameters(
  576 + qpdf_data qpdf, char const* user_password, char const* owner_password,
  577 + QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract,
  578 + qpdf_r3_print_e print, qpdf_r3_modify_e modify,
  579 + QPDF_BOOL encrypt_metadata)
  580 +{
  581 + QTC::TC("qpdf", "qpdf-c called qpdf_set_r5_encryption_parameters");
  582 + qpdf->qpdf_writer->setR5EncryptionParameters(
  583 + user_password, owner_password,
  584 + allow_accessibility, allow_extract, print, modify,
  585 + encrypt_metadata);
  586 +}
  587 +
  588 +void qpdf_set_r6_encryption_parameters(
  589 + qpdf_data qpdf, char const* user_password, char const* owner_password,
  590 + QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract,
  591 + qpdf_r3_print_e print, qpdf_r3_modify_e modify,
  592 + QPDF_BOOL encrypt_metadata)
  593 +{
  594 + QTC::TC("qpdf", "qpdf-c called qpdf_set_r6_encryption_parameters");
  595 + qpdf->qpdf_writer->setR6EncryptionParameters(
  596 + user_password, owner_password,
  597 + allow_accessibility, allow_extract, print, modify,
  598 + encrypt_metadata);
  599 +}
  600 +
569 void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value) 601 void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value)
570 { 602 {
571 QTC::TC("qpdf", "qpdf-c called qpdf_set_linearization"); 603 QTC::TC("qpdf", "qpdf-c called qpdf_set_linearization");
@@ -574,14 +606,26 @@ void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value) @@ -574,14 +606,26 @@ void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value)
574 606
575 void qpdf_set_minimum_pdf_version(qpdf_data qpdf, char const* version) 607 void qpdf_set_minimum_pdf_version(qpdf_data qpdf, char const* version)
576 { 608 {
  609 + qpdf_set_minimum_pdf_version_and_extension(qpdf, version, 0);
  610 +}
  611 +
  612 +void qpdf_set_minimum_pdf_version_and_extension(
  613 + qpdf_data qpdf, char const* version, int extension_level)
  614 +{
577 QTC::TC("qpdf", "qpdf-c called qpdf_set_minimum_pdf_version"); 615 QTC::TC("qpdf", "qpdf-c called qpdf_set_minimum_pdf_version");
578 - qpdf->qpdf_writer->setMinimumPDFVersion(version); 616 + qpdf->qpdf_writer->setMinimumPDFVersion(version, extension_level);
579 } 617 }
580 618
581 void qpdf_force_pdf_version(qpdf_data qpdf, char const* version) 619 void qpdf_force_pdf_version(qpdf_data qpdf, char const* version)
582 { 620 {
  621 + qpdf_force_pdf_version_and_extension(qpdf, version, 0);
  622 +}
  623 +
  624 +void qpdf_force_pdf_version_and_extension(
  625 + qpdf_data qpdf, char const* version, int extension_level)
  626 +{
583 QTC::TC("qpdf", "qpdf-c called qpdf_force_pdf_version"); 627 QTC::TC("qpdf", "qpdf-c called qpdf_force_pdf_version");
584 - qpdf->qpdf_writer->forcePDFVersion(version); 628 + qpdf->qpdf_writer->forcePDFVersion(version, extension_level);
585 } 629 }
586 630
587 QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf) 631 QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf)
qpdf/qpdf-ctest.c
@@ -106,6 +106,10 @@ static void test01(char const* infile, @@ -106,6 +106,10 @@ static void test01(char const* infile,
106 { 106 {
107 qpdf_read(qpdf, infile, password); 107 qpdf_read(qpdf, infile, password);
108 printf("version: %s\n", qpdf_get_pdf_version(qpdf)); 108 printf("version: %s\n", qpdf_get_pdf_version(qpdf));
  109 + if (qpdf_get_pdf_extension_level(qpdf) > 0)
  110 + {
  111 + printf("extension level: %d\n", qpdf_get_pdf_extension_level(qpdf));
  112 + }
109 printf("linearized: %d\n", qpdf_is_linearized(qpdf)); 113 printf("linearized: %d\n", qpdf_is_linearized(qpdf));
110 printf("encrypted: %d\n", qpdf_is_encrypted(qpdf)); 114 printf("encrypted: %d\n", qpdf_is_encrypted(qpdf));
111 if (qpdf_is_encrypted(qpdf)) 115 if (qpdf_is_encrypted(qpdf))
@@ -304,7 +308,7 @@ static void test14(char const* infile, @@ -304,7 +308,7 @@ static void test14(char const* infile,
304 qpdf_read(qpdf, infile, password); 308 qpdf_read(qpdf, infile, password);
305 qpdf_init_write(qpdf, outfile); 309 qpdf_init_write(qpdf, outfile);
306 qpdf_set_static_ID(qpdf, QPDF_TRUE); 310 qpdf_set_static_ID(qpdf, QPDF_TRUE);
307 - qpdf_set_minimum_pdf_version(qpdf, "1.6"); 311 + qpdf_set_minimum_pdf_version_and_extension(qpdf, "1.7", 8);
308 qpdf_write(qpdf); 312 qpdf_write(qpdf);
309 qpdf_init_write(qpdf, outfile2); 313 qpdf_init_write(qpdf, outfile2);
310 qpdf_set_static_ID(qpdf, QPDF_TRUE); 314 qpdf_set_static_ID(qpdf, QPDF_TRUE);
@@ -374,6 +378,38 @@ static void test16(char const* infile, @@ -374,6 +378,38 @@ static void test16(char const* infile,
374 report_errors(); 378 report_errors();
375 } 379 }
376 380
  381 +static void test17(char const* infile,
  382 + char const* password,
  383 + char const* outfile,
  384 + char const* outfile2)
  385 +{
  386 + qpdf_read(qpdf, infile, password);
  387 + qpdf_init_write(qpdf, outfile);
  388 + qpdf_set_static_ID(qpdf, QPDF_TRUE);
  389 + qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
  390 + qpdf_set_r5_encryption_parameters(
  391 + qpdf, "user3", "owner3", QPDF_TRUE, QPDF_TRUE,
  392 + qpdf_r3p_low, qpdf_r3m_all, QPDF_TRUE);
  393 + qpdf_write(qpdf);
  394 + report_errors();
  395 +}
  396 +
  397 +static void test18(char const* infile,
  398 + char const* password,
  399 + char const* outfile,
  400 + char const* outfile2)
  401 +{
  402 + qpdf_read(qpdf, infile, password);
  403 + qpdf_init_write(qpdf, outfile);
  404 + qpdf_set_static_ID(qpdf, QPDF_TRUE);
  405 + qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
  406 + qpdf_set_r6_encryption_parameters(
  407 + qpdf, "user4", "owner4", QPDF_TRUE, QPDF_TRUE,
  408 + qpdf_r3p_low, qpdf_r3m_all, QPDF_TRUE);
  409 + qpdf_write(qpdf);
  410 + report_errors();
  411 +}
  412 +
377 int main(int argc, char* argv[]) 413 int main(int argc, char* argv[])
378 { 414 {
379 char* p = 0; 415 char* p = 0;
@@ -430,6 +466,8 @@ int main(int argc, char* argv[]) @@ -430,6 +466,8 @@ int main(int argc, char* argv[])
430 (n == 14) ? test14 : 466 (n == 14) ? test14 :
431 (n == 15) ? test15 : 467 (n == 15) ? test15 :
432 (n == 16) ? test16 : 468 (n == 16) ? test16 :
  469 + (n == 17) ? test17 :
  470 + (n == 18) ? test18 :
433 0); 471 0);
434 472
435 if (fn == 0) 473 if (fn == 0)
qpdf/qpdf.testcov
@@ -256,3 +256,6 @@ QPDF_encryption skip 0x28 0 @@ -256,3 +256,6 @@ QPDF_encryption skip 0x28 0
256 QPDF_encrypt crypt array 0 256 QPDF_encrypt crypt array 0
257 QPDF_encryption CFM AESV3 0 257 QPDF_encryption CFM AESV3 0
258 QPDFWriter remove Crypt 0 258 QPDFWriter remove Crypt 0
  259 +qpdf-c called qpdf_get_pdf_extension_level 0
  260 +qpdf-c called qpdf_set_r5_encryption_parameters 0
  261 +qpdf-c called qpdf_set_r6_encryption_parameters 0
qpdf/qtest/qpdf.test
@@ -315,8 +315,8 @@ $td-&gt;runtest(&quot;C API: min/force versions&quot;, @@ -315,8 +315,8 @@ $td-&gt;runtest(&quot;C API: min/force versions&quot;,
315 $td->EXIT_STATUS => 0}, 315 $td->EXIT_STATUS => 0},
316 $td->NORMALIZE_NEWLINES); 316 $td->NORMALIZE_NEWLINES);
317 $td->runtest("C check version 1", 317 $td->runtest("C check version 1",
318 - {$td->COMMAND => "qpdf --check a.pdf"},  
319 - {$td->FILE => "min-version.out", 318 + {$td->COMMAND => "qpdf-ctest 1 a.pdf '' ''"},
  319 + {$td->FILE => "c-min-version.out",
320 $td->EXIT_STATUS => 0}, 320 $td->EXIT_STATUS => 0},
321 $td->NORMALIZE_NEWLINES); 321 $td->NORMALIZE_NEWLINES);
322 $td->runtest("C check version 2", 322 $td->runtest("C check version 2",
@@ -1472,29 +1472,52 @@ $td-&gt;runtest(&quot;C API: invalid password&quot;, @@ -1472,29 +1472,52 @@ $td-&gt;runtest(&quot;C API: invalid password&quot;,
1472 $td->NORMALIZE_NEWLINES); 1472 $td->NORMALIZE_NEWLINES);
1473 1473
1474 my @cenc = ( 1474 my @cenc = (
1475 - [11, 'hybrid-xref.pdf', "''", 'r2', ""],  
1476 - [12, 'hybrid-xref.pdf', "''", 'r3', ""],  
1477 - [15, 'hybrid-xref.pdf', "''", 'r4', ""], 1475 + [11, 'hybrid-xref.pdf', "''", 'r2', "", ""],
  1476 + [12, 'hybrid-xref.pdf', "''", 'r3', "", ""],
  1477 + [15, 'hybrid-xref.pdf', "''", 'r4', "", ""],
  1478 + [17, 'hybrid-xref.pdf', "''", 'r5', "", "owner3"],
  1479 + [18, 'hybrid-xref.pdf', "''", 'r6', "", "user4"],
1478 [13, 'c-r2.pdf', 'user1', 'decrypt with user', 1480 [13, 'c-r2.pdf', 'user1', 'decrypt with user',
1479 - "user password: user1\n"], 1481 + "user password: user1\n", ""],
1480 [13, 'c-r3.pdf', 'owner2', 'decrypt with owner', 1482 [13, 'c-r3.pdf', 'owner2', 'decrypt with owner',
1481 - "user password: user2\n"], 1483 + "user password: user2\n", ""],
  1484 + [13, 'c-r5-in.pdf', 'user3', 'decrypt R5 with user',
  1485 + "user password: user3\n", ""],
  1486 + [13, 'c-r6-in.pdf', 'owner4', 'decrypt R6 with owner',
  1487 + "user password: \n", ""],
1482 ); 1488 );
1483 $n_tests += 2 * @cenc; 1489 $n_tests += 2 * @cenc;
1484 1490
1485 foreach my $d (@cenc) 1491 foreach my $d (@cenc)
1486 { 1492 {
1487 - my ($n, $infile, $pass, $description, $output) = @$d; 1493 + my ($n, $infile, $pass, $description, $output, $checkpass) = @$d;
1488 my $outfile = $description; 1494 my $outfile = $description;
1489 $outfile =~ s/ /-/g; 1495 $outfile =~ s/ /-/g;
1490 - $outfile = "c-$outfile.pdf"; 1496 + my $pdf_outfile = "c-$outfile.pdf";
  1497 + my $check_outfile = "c-$outfile.out";
1491 $td->runtest("C API encryption: $description", 1498 $td->runtest("C API encryption: $description",
1492 {$td->COMMAND => "qpdf-ctest $n $infile $pass a.pdf"}, 1499 {$td->COMMAND => "qpdf-ctest $n $infile $pass a.pdf"},
1493 {$td->STRING => $output, $td->EXIT_STATUS => 0}, 1500 {$td->STRING => $output, $td->EXIT_STATUS => 0},
1494 $td->NORMALIZE_NEWLINES); 1501 $td->NORMALIZE_NEWLINES);
1495 - $td->runtest("check $description",  
1496 - {$td->FILE => "a.pdf"},  
1497 - {$td->FILE => $outfile}); 1502 + if (-f $pdf_outfile)
  1503 + {
  1504 + $td->runtest("check $description content",
  1505 + {$td->FILE => "a.pdf"},
  1506 + {$td->FILE => $pdf_outfile});
  1507 + }
  1508 + else
  1509 + {
  1510 + # QPDF doesn't provide any way to make the random bits in
  1511 + # /Perms static, so we have no way to predictably create a
  1512 + # /V=5 encrypted file. It's not worth adding this...the test
  1513 + # suite is adequate without having a statically predictable
  1514 + # file.
  1515 + $td->runtest("check $description",
  1516 + {$td->COMMAND =>
  1517 + "qpdf --check a.pdf --password=$checkpass"},
  1518 + {$td->FILE => $check_outfile, $td->EXIT_STATUS => 0},
  1519 + $td->NORMALIZE_NEWLINES);
  1520 + }
1498 } 1521 }
1499 1522
1500 # Test combinations of linearization and encryption. Note that we do 1523 # Test combinations of linearization and encryption. Note that we do
qpdf/qtest/qpdf/c-decrypt-R5-with-user.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/c-decrypt-R6-with-owner.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/c-min-version.out 0 → 100644
  1 +version: 1.7
  2 +extension level: 8
  3 +linearized: 0
  4 +encrypted: 0
qpdf/qtest/qpdf/c-r5-in.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/c-r5.out 0 → 100644
  1 +checking a.pdf
  2 +PDF Version: 1.7 extension level 3
  3 +R = 5
  4 +P = -2052
  5 +User password =
  6 +extract for accessibility: allowed
  7 +extract for any purpose: allowed
  8 +print low resolution: allowed
  9 +print high resolution: not allowed
  10 +modify document assembly: allowed
  11 +modify forms: allowed
  12 +modify annotations: allowed
  13 +modify other: allowed
  14 +modify anything: allowed
  15 +stream encryption method: AESv3
  16 +string encryption method: AESv3
  17 +file encryption method: AESv3
  18 +File is not linearized
  19 +No syntax or stream encoding errors found; the file may still contain
  20 +errors that qpdf cannot detect
qpdf/qtest/qpdf/c-r6-in.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/c-r6.out 0 → 100644
  1 +checking a.pdf
  2 +PDF Version: 1.7 extension level 8
  3 +R = 6
  4 +P = -2052
  5 +User password = user4
  6 +extract for accessibility: allowed
  7 +extract for any purpose: allowed
  8 +print low resolution: allowed
  9 +print high resolution: not allowed
  10 +modify document assembly: allowed
  11 +modify forms: allowed
  12 +modify annotations: allowed
  13 +modify other: allowed
  14 +modify anything: allowed
  15 +stream encryption method: AESv3
  16 +string encryption method: AESv3
  17 +file encryption method: AESv3
  18 +File is not linearized
  19 +No syntax or stream encoding errors found; the file may still contain
  20 +errors that qpdf cannot detect