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 10 2012-12-30 Jay Berkenbilt <ejb@ql.org>
2 11  
3 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 213 QPDF_DLL
214 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 220 /* Return the user password. If the file is opened using the
217 221 * owner password, the user password may be retrieved using this
218 222 * function. If the file is opened using the user password, this
... ... @@ -359,14 +363,36 @@ extern &quot;C&quot; {
359 363 QPDF_BOOL encrypt_metadata, QPDF_BOOL use_aes);
360 364  
361 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 380 void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value);
363 381  
364 382 QPDF_DLL
365 383 void qpdf_set_minimum_pdf_version(qpdf_data qpdf, char const* version);
366 384  
367 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 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 396 /* Do actual write operation. */
371 397 QPDF_DLL
372 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 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 297 char const* qpdf_get_user_password(qpdf_data qpdf)
292 298 {
293 299 QTC::TC("qpdf", "qpdf-c called qpdf_get_user_password");
... ... @@ -566,6 +572,32 @@ void qpdf_set_r4_encryption_parameters(
566 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 601 void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value)
570 602 {
571 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 606  
575 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 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 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 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 631 QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf)
... ...
qpdf/qpdf-ctest.c
... ... @@ -106,6 +106,10 @@ static void test01(char const* infile,
106 106 {
107 107 qpdf_read(qpdf, infile, password);
108 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 113 printf("linearized: %d\n", qpdf_is_linearized(qpdf));
110 114 printf("encrypted: %d\n", qpdf_is_encrypted(qpdf));
111 115 if (qpdf_is_encrypted(qpdf))
... ... @@ -304,7 +308,7 @@ static void test14(char const* infile,
304 308 qpdf_read(qpdf, infile, password);
305 309 qpdf_init_write(qpdf, outfile);
306 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 312 qpdf_write(qpdf);
309 313 qpdf_init_write(qpdf, outfile2);
310 314 qpdf_set_static_ID(qpdf, QPDF_TRUE);
... ... @@ -374,6 +378,38 @@ static void test16(char const* infile,
374 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 413 int main(int argc, char* argv[])
378 414 {
379 415 char* p = 0;
... ... @@ -430,6 +466,8 @@ int main(int argc, char* argv[])
430 466 (n == 14) ? test14 :
431 467 (n == 15) ? test15 :
432 468 (n == 16) ? test16 :
  469 + (n == 17) ? test17 :
  470 + (n == 18) ? test18 :
433 471 0);
434 472  
435 473 if (fn == 0)
... ...
qpdf/qpdf.testcov
... ... @@ -256,3 +256,6 @@ QPDF_encryption skip 0x28 0
256 256 QPDF_encrypt crypt array 0
257 257 QPDF_encryption CFM AESV3 0
258 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 315 $td->EXIT_STATUS => 0},
316 316 $td->NORMALIZE_NEWLINES);
317 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 320 $td->EXIT_STATUS => 0},
321 321 $td->NORMALIZE_NEWLINES);
322 322 $td->runtest("C check version 2",
... ... @@ -1472,29 +1472,52 @@ $td-&gt;runtest(&quot;C API: invalid password&quot;,
1472 1472 $td->NORMALIZE_NEWLINES);
1473 1473  
1474 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 1480 [13, 'c-r2.pdf', 'user1', 'decrypt with user',
1479   - "user password: user1\n"],
  1481 + "user password: user1\n", ""],
1480 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 1489 $n_tests += 2 * @cenc;
1484 1490  
1485 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 1494 my $outfile = $description;
1489 1495 $outfile =~ s/ /-/g;
1490   - $outfile = "c-$outfile.pdf";
  1496 + my $pdf_outfile = "c-$outfile.pdf";
  1497 + my $check_outfile = "c-$outfile.out";
1491 1498 $td->runtest("C API encryption: $description",
1492 1499 {$td->COMMAND => "qpdf-ctest $n $infile $pass a.pdf"},
1493 1500 {$td->STRING => $output, $td->EXIT_STATUS => 0},
1494 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 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
... ...