Commit fcdbc8a102ca258d105ebd2f41bbf17b29c817fd
1 parent
c4e56fa5
Move doFinalChecks to QPDFJob::checkConfiguration
Showing
3 changed files
with
99 additions
and
72 deletions
include/qpdf/QPDFJob.hh
| @@ -85,6 +85,14 @@ class QPDFJob | @@ -85,6 +85,14 @@ class QPDFJob | ||
| 85 | QPDF_DLL | 85 | QPDF_DLL |
| 86 | void setOutputStreams(std::ostream* out_stream, std::ostream* err_stream); | 86 | void setOutputStreams(std::ostream* out_stream, std::ostream* err_stream); |
| 87 | 87 | ||
| 88 | + // Check to make sure no contradictory options have been | ||
| 89 | + // specified. This is called automatically after initializing from | ||
| 90 | + // argv or json and is also called by run, but you can call it | ||
| 91 | + // manually as well. It throws a Usage exception if there are any | ||
| 92 | + // errors. | ||
| 93 | + QPDF_DLL | ||
| 94 | + void checkConfiguration(); | ||
| 95 | + | ||
| 88 | // Returns true if output is created by the specified job. | 96 | // Returns true if output is created by the specified job. |
| 89 | QPDF_DLL | 97 | QPDF_DLL |
| 90 | bool createsOutput() const; | 98 | bool createsOutput() const; |
libqpdf/QPDFJob.cc
| @@ -530,6 +530,93 @@ QPDFJob::createsOutput() const | @@ -530,6 +530,93 @@ QPDFJob::createsOutput() const | ||
| 530 | return ((o.outfilename != nullptr) || o.replace_input); | 530 | return ((o.outfilename != nullptr) || o.replace_input); |
| 531 | } | 531 | } |
| 532 | 532 | ||
| 533 | +void | ||
| 534 | +QPDFJob::checkConfiguration() | ||
| 535 | +{ | ||
| 536 | + auto usage = [](char const* msg){ | ||
| 537 | + throw std::runtime_error(msg); | ||
| 538 | + }; | ||
| 539 | + | ||
| 540 | + QPDFJob& o = *this; // QXXXQ | ||
| 541 | + // QXXXQ messages are CLI-centric | ||
| 542 | + if (o.replace_input) | ||
| 543 | + { | ||
| 544 | + if (o.outfilename) | ||
| 545 | + { | ||
| 546 | + usage("--replace-input may not be used when" | ||
| 547 | + " an output file is specified"); | ||
| 548 | + } | ||
| 549 | + else if (o.split_pages) | ||
| 550 | + { | ||
| 551 | + usage("--split-pages may not be used with --replace-input"); | ||
| 552 | + } | ||
| 553 | + } | ||
| 554 | + if (o.infilename == 0) | ||
| 555 | + { | ||
| 556 | + usage("an input file name is required"); | ||
| 557 | + } | ||
| 558 | + else if (o.require_outfile && (o.outfilename == 0) && (! o.replace_input)) | ||
| 559 | + { | ||
| 560 | + usage("an output file name is required; use - for standard output"); | ||
| 561 | + } | ||
| 562 | + else if ((! o.require_outfile) && | ||
| 563 | + ((o.outfilename != 0) || o.replace_input)) | ||
| 564 | + { | ||
| 565 | + usage("no output file may be given for this option"); | ||
| 566 | + } | ||
| 567 | + if (o.check_requires_password && o.check_is_encrypted) | ||
| 568 | + { | ||
| 569 | + usage("--requires-password and --is-encrypted may not be given" | ||
| 570 | + " together"); | ||
| 571 | + } | ||
| 572 | + | ||
| 573 | + if (o.encrypt && (! o.allow_insecure) && | ||
| 574 | + (o.owner_password.empty() && | ||
| 575 | + (! o.user_password.empty()) && | ||
| 576 | + (o.keylen == 256))) | ||
| 577 | + { | ||
| 578 | + // Note that empty owner passwords for R < 5 are copied from | ||
| 579 | + // the user password, so this lack of security is not an issue | ||
| 580 | + // for those files. Also we are consider only the ability to | ||
| 581 | + // open the file without a password to be insecure. We are not | ||
| 582 | + // concerned about whether the viewer enforces security | ||
| 583 | + // settings when the user and owner password match. | ||
| 584 | + usage("A PDF with a non-empty user password and an empty owner" | ||
| 585 | + " password encrypted with a 256-bit key is insecure as it" | ||
| 586 | + " can be opened without a password. If you really want to" | ||
| 587 | + " do this, you must also give the --allow-insecure option" | ||
| 588 | + " before the -- that follows --encrypt."); | ||
| 589 | + } | ||
| 590 | + | ||
| 591 | + if (o.require_outfile && o.outfilename && | ||
| 592 | + (strcmp(o.outfilename.get(), "-") == 0)) | ||
| 593 | + { | ||
| 594 | + if (o.split_pages) | ||
| 595 | + { | ||
| 596 | + usage("--split-pages may not be used when" | ||
| 597 | + " writing to standard output"); | ||
| 598 | + } | ||
| 599 | + if (o.verbose) | ||
| 600 | + { | ||
| 601 | + usage("--verbose may not be used when" | ||
| 602 | + " writing to standard output"); | ||
| 603 | + } | ||
| 604 | + if (o.progress) | ||
| 605 | + { | ||
| 606 | + usage("--progress may not be used when" | ||
| 607 | + " writing to standard output"); | ||
| 608 | + } | ||
| 609 | + } | ||
| 610 | + | ||
| 611 | + if ((! o.split_pages) && | ||
| 612 | + QUtil::same_file(o.infilename.get(), o.outfilename.get())) | ||
| 613 | + { | ||
| 614 | + QTC::TC("qpdf", "qpdf same file error"); | ||
| 615 | + usage("input file and output file are the same;" | ||
| 616 | + " use --replace-input to intentionally overwrite the input file"); | ||
| 617 | + } | ||
| 618 | +} | ||
| 619 | + | ||
| 533 | bool | 620 | bool |
| 534 | QPDFJob::suppressWarnings() | 621 | QPDFJob::suppressWarnings() |
| 535 | { | 622 | { |
libqpdf/QPDFJob_argv.cc
| @@ -1474,81 +1474,13 @@ ArgParser::parseOptions() | @@ -1474,81 +1474,13 @@ ArgParser::parseOptions() | ||
| 1474 | void | 1474 | void |
| 1475 | ArgParser::doFinalChecks() | 1475 | ArgParser::doFinalChecks() |
| 1476 | { | 1476 | { |
| 1477 | - if (o.replace_input) | ||
| 1478 | - { | ||
| 1479 | - if (o.outfilename) | ||
| 1480 | - { | ||
| 1481 | - usage("--replace-input may not be used when" | ||
| 1482 | - " an output file is specified"); | ||
| 1483 | - } | ||
| 1484 | - else if (o.split_pages) | ||
| 1485 | - { | ||
| 1486 | - usage("--split-pages may not be used with --replace-input"); | ||
| 1487 | - } | ||
| 1488 | - } | ||
| 1489 | - if (o.infilename == 0) | ||
| 1490 | - { | ||
| 1491 | - usage("an input file name is required"); | ||
| 1492 | - } | ||
| 1493 | - else if (o.require_outfile && (o.outfilename == 0) && (! o.replace_input)) | ||
| 1494 | - { | ||
| 1495 | - usage("an output file name is required; use - for standard output"); | ||
| 1496 | - } | ||
| 1497 | - else if ((! o.require_outfile) && | ||
| 1498 | - ((o.outfilename != 0) || o.replace_input)) | ||
| 1499 | - { | ||
| 1500 | - usage("no output file may be given for this option"); | ||
| 1501 | - } | ||
| 1502 | - if (o.check_requires_password && o.check_is_encrypted) | ||
| 1503 | - { | ||
| 1504 | - usage("--requires-password and --is-encrypted may not be given" | ||
| 1505 | - " together"); | ||
| 1506 | - } | ||
| 1507 | - | ||
| 1508 | - if (o.encrypt && (! o.allow_insecure) && | ||
| 1509 | - (o.owner_password.empty() && | ||
| 1510 | - (! o.user_password.empty()) && | ||
| 1511 | - (o.keylen == 256))) | ||
| 1512 | - { | ||
| 1513 | - // Note that empty owner passwords for R < 5 are copied from | ||
| 1514 | - // the user password, so this lack of security is not an issue | ||
| 1515 | - // for those files. Also we are consider only the ability to | ||
| 1516 | - // open the file without a password to be insecure. We are not | ||
| 1517 | - // concerned about whether the viewer enforces security | ||
| 1518 | - // settings when the user and owner password match. | ||
| 1519 | - usage("A PDF with a non-empty user password and an empty owner" | ||
| 1520 | - " password encrypted with a 256-bit key is insecure as it" | ||
| 1521 | - " can be opened without a password. If you really want to" | ||
| 1522 | - " do this, you must also give the --allow-insecure option" | ||
| 1523 | - " before the -- that follows --encrypt."); | ||
| 1524 | - } | ||
| 1525 | - | ||
| 1526 | - if (o.require_outfile && o.outfilename && | ||
| 1527 | - (strcmp(o.outfilename.get(), "-") == 0)) | 1477 | + try |
| 1528 | { | 1478 | { |
| 1529 | - if (o.split_pages) | ||
| 1530 | - { | ||
| 1531 | - usage("--split-pages may not be used when" | ||
| 1532 | - " writing to standard output"); | ||
| 1533 | - } | ||
| 1534 | - if (o.verbose) | ||
| 1535 | - { | ||
| 1536 | - usage("--verbose may not be used when" | ||
| 1537 | - " writing to standard output"); | ||
| 1538 | - } | ||
| 1539 | - if (o.progress) | ||
| 1540 | - { | ||
| 1541 | - usage("--progress may not be used when" | ||
| 1542 | - " writing to standard output"); | ||
| 1543 | - } | 1479 | + o.checkConfiguration(); |
| 1544 | } | 1480 | } |
| 1545 | - | ||
| 1546 | - if ((! o.split_pages) && | ||
| 1547 | - QUtil::same_file(o.infilename.get(), o.outfilename.get())) | 1481 | + catch (std::runtime_error& e) |
| 1548 | { | 1482 | { |
| 1549 | - QTC::TC("qpdf", "qpdf same file error"); | ||
| 1550 | - usage("input file and output file are the same;" | ||
| 1551 | - " use --replace-input to intentionally overwrite the input file"); | 1483 | + usage(e.what()); |
| 1552 | } | 1484 | } |
| 1553 | } | 1485 | } |
| 1554 | 1486 |