Commit 3c075fc01740a955eb8f192f565bf1f6c029c73e

Authored by Jay Berkenbilt
1 parent 245723c5

Table-driven parsing of encrypt options

Showing 1 changed file with 277 additions and 384 deletions
qpdf/qpdf.cc
... ... @@ -329,13 +329,25 @@ class ArgParser
329 329 void argWithImages();
330 330 void argShowJson();
331 331 void argCheck();
  332 + void arg40Print(char* parameter);
  333 + void arg40Modify(char* parameter);
  334 + void arg40Extract(char* parameter);
  335 + void arg40Annotate(char* parameter);
  336 + void arg128Accessibility(char* parameter);
  337 + void arg128Extract(char* parameter);
  338 + void arg128Print(char* parameter);
  339 + void arg128Modify(char* parameter);
  340 + void arg128ClearTextMetadata();
  341 + void arg128UseAes(char* parameter);
  342 + void arg128ForceV4();
  343 + void arg256ForceR5();
  344 + void argEndEncrypt();
332 345  
333 346 void usage(std::string const& message);
334 347 void initOptionTable();
335 348 void handleHelpVersion();
336 349 void handleArgFileArguments();
337 350 void readArgsFromFile(char const* filename);
338   - void parseEncryptOptions();
339 351 std::vector<PageSpec> parsePagesOptions();
340 352 void parseRotationParameter(std::string const&);
341 353 std::vector<int> parseNumrange(char const* range, int max,
... ... @@ -348,7 +360,11 @@ class ArgParser
348 360 Options& o;
349 361 int cur_arg;
350 362  
351   - std::map<std::string, OptionEntry> option_table;
  363 + std::map<std::string, OptionEntry>* option_table;
  364 + std::map<std::string, OptionEntry> main_option_table;
  365 + std::map<std::string, OptionEntry> encrypt40_option_table;
  366 + std::map<std::string, OptionEntry> encrypt128_option_table;
  367 + std::map<std::string, OptionEntry> encrypt256_option_table;
352 368 std::vector<PointerHolder<char> > new_argv;
353 369 PointerHolder<char*> argv_ph;
354 370 };
... ... @@ -359,6 +375,7 @@ ArgParser::ArgParser(int argc, char* argv[], Options&amp; o) :
359 375 o(o),
360 376 cur_arg(0)
361 377 {
  378 + option_table = &main_option_table;
362 379 initOptionTable();
363 380 }
364 381  
... ... @@ -414,75 +431,107 @@ ArgParser::oe_requiredChoices(param_arg_handler_t h, char const** choices)
414 431 void
415 432 ArgParser::initOptionTable()
416 433 {
417   - std::map<std::string, OptionEntry>& t = this->option_table;
  434 + std::map<std::string, OptionEntry>* t = &this->main_option_table;
418 435 char const* yn[] = {"y", "n", 0};
419   - t[""] = oe_positional(&ArgParser::argPositional);
420   - t["password"] = oe_requiredParameter(&ArgParser::argPassword, "pass");
421   - t["empty"] = oe_bare(&ArgParser::argEmpty);
422   - t["linearize"] = oe_bare(&ArgParser::argLinearize);
423   - t["encrypt"] = oe_bare(&ArgParser::argEncrypt);
424   - t["decrypt"] = oe_bare(&ArgParser::argDecrypt);
425   - t["password-is-hex-key"] = oe_bare(&ArgParser::argPasswordIsHexKey);
426   - t["copy-encryption"] = oe_requiredParameter(
  436 + (*t)[""] = oe_positional(&ArgParser::argPositional);
  437 + (*t)["password"] = oe_requiredParameter(&ArgParser::argPassword, "pass");
  438 + (*t)["empty"] = oe_bare(&ArgParser::argEmpty);
  439 + (*t)["linearize"] = oe_bare(&ArgParser::argLinearize);
  440 + (*t)["encrypt"] = oe_bare(&ArgParser::argEncrypt);
  441 + (*t)["decrypt"] = oe_bare(&ArgParser::argDecrypt);
  442 + (*t)["password-is-hex-key"] = oe_bare(&ArgParser::argPasswordIsHexKey);
  443 + (*t)["copy-encryption"] = oe_requiredParameter(
427 444 &ArgParser::argCopyEncryption, "file");
428   - t["encryption-file-password"] = oe_requiredParameter(
  445 + (*t)["encryption-file-password"] = oe_requiredParameter(
429 446 &ArgParser::argEncryptionFilePassword, "password");
430   - t["pages"] = oe_bare(&ArgParser::argPages);
431   - t["rotate"] = oe_requiredParameter(
  447 + (*t)["pages"] = oe_bare(&ArgParser::argPages);
  448 + (*t)["rotate"] = oe_requiredParameter(
432 449 &ArgParser::argRotate, "[+|-]angle:page-range");
433 450 char const* streamDataChoices[] =
434 451 {"compress", "preserve", "uncompress", 0};
435   - t["stream-data"] = oe_requiredChoices(
  452 + (*t)["stream-data"] = oe_requiredChoices(
436 453 &ArgParser::argStreamData, streamDataChoices);
437   - t["compress-streams"] = oe_requiredChoices(
  454 + (*t)["compress-streams"] = oe_requiredChoices(
438 455 &ArgParser::argCompressStreams, yn);
439 456 char const* decodeLevelChoices[] =
440 457 {"none", "generalized", "specialized", "all", 0};
441   - t["decode-level"] = oe_requiredChoices(
  458 + (*t)["decode-level"] = oe_requiredChoices(
442 459 &ArgParser::argDecodeLevel, decodeLevelChoices);
443   - t["normalize-content"] = oe_requiredChoices(
  460 + (*t)["normalize-content"] = oe_requiredChoices(
444 461 &ArgParser::argNormalizeContent, yn);
445   - t["suppress-recovery"] = oe_bare(&ArgParser::argSuppressRecovery);
  462 + (*t)["suppress-recovery"] = oe_bare(&ArgParser::argSuppressRecovery);
446 463 char const* objectStreamsChoices[] = {"disable", "preserve", "generate", 0};
447   - t["object-streams"] = oe_requiredChoices(
  464 + (*t)["object-streams"] = oe_requiredChoices(
448 465 &ArgParser::argObjectStreams, objectStreamsChoices);
449   - t["ignore-xref-streams"] = oe_bare(&ArgParser::argIgnoreXrefStreams);
450   - t["qdf"] = oe_bare(&ArgParser::argQdf);
451   - t["preserve-unreferenced"] = oe_bare(&ArgParser::argPreserveUnreferenced);
452   - t["preserve-unreferenced-resources"] = oe_bare(
  466 + (*t)["ignore-xref-streams"] = oe_bare(&ArgParser::argIgnoreXrefStreams);
  467 + (*t)["qdf"] = oe_bare(&ArgParser::argQdf);
  468 + (*t)["preserve-unreferenced"] = oe_bare(
  469 + &ArgParser::argPreserveUnreferenced);
  470 + (*t)["preserve-unreferenced-resources"] = oe_bare(
453 471 &ArgParser::argPreserveUnreferencedResources);
454   - t["keep-files-open"] = oe_requiredChoices(&ArgParser::argKeepFilesOpen, yn);
455   - t["newline-before-endstream"] = oe_bare(
  472 + (*t)["keep-files-open"] = oe_requiredChoices(
  473 + &ArgParser::argKeepFilesOpen, yn);
  474 + (*t)["newline-before-endstream"] = oe_bare(
456 475 &ArgParser::argNewlineBeforeEndstream);
457   - t["linearize-pass1"] = oe_requiredParameter(
  476 + (*t)["linearize-pass1"] = oe_requiredParameter(
458 477 &ArgParser::argLinearizePass1, "filename");
459   - t["coalesce-contents"] = oe_bare(&ArgParser::argCoalesceContents);
460   - t["min-version"] = oe_requiredParameter(
  478 + (*t)["coalesce-contents"] = oe_bare(&ArgParser::argCoalesceContents);
  479 + (*t)["min-version"] = oe_requiredParameter(
461 480 &ArgParser::argMinVersion, "version");
462   - t["force-version"] = oe_requiredParameter(
  481 + (*t)["force-version"] = oe_requiredParameter(
463 482 &ArgParser::argForceVersion, "version");
464   - t["split-pages"] = oe_optionalParameter(&ArgParser::argSplitPages);
465   - t["verbose"] = oe_bare(&ArgParser::argVerbose);
466   - t["progress"] = oe_bare(&ArgParser::argProgress);
467   - t["no-warn"] = oe_bare(&ArgParser::argNoWarn);
468   - t["deterministic-id"] = oe_bare(&ArgParser::argDeterministicId);
469   - t["static-id"] = oe_bare(&ArgParser::argStaticId);
470   - t["static-aes-iv"] = oe_bare(&ArgParser::argStaticAesIv);
471   - t["no-original-object-ids"] = oe_bare(&ArgParser::argNoOriginalObjectIds);
472   - t["show-encryption"] = oe_bare(&ArgParser::argShowEncryption);
473   - t["show-encryption-key"] = oe_bare(&ArgParser::argShowEncryptionKey);
474   - t["check-linearization"] = oe_bare(&ArgParser::argCheckLinearization);
475   - t["show-linearization"] = oe_bare(&ArgParser::argShowLinearization);
476   - t["show-xref"] = oe_bare(&ArgParser::argShowXref);
477   - t["show-object"] = oe_requiredParameter(
  483 + (*t)["split-pages"] = oe_optionalParameter(&ArgParser::argSplitPages);
  484 + (*t)["verbose"] = oe_bare(&ArgParser::argVerbose);
  485 + (*t)["progress"] = oe_bare(&ArgParser::argProgress);
  486 + (*t)["no-warn"] = oe_bare(&ArgParser::argNoWarn);
  487 + (*t)["deterministic-id"] = oe_bare(&ArgParser::argDeterministicId);
  488 + (*t)["static-id"] = oe_bare(&ArgParser::argStaticId);
  489 + (*t)["static-aes-iv"] = oe_bare(&ArgParser::argStaticAesIv);
  490 + (*t)["no-original-object-ids"] = oe_bare(
  491 + &ArgParser::argNoOriginalObjectIds);
  492 + (*t)["show-encryption"] = oe_bare(&ArgParser::argShowEncryption);
  493 + (*t)["show-encryption-key"] = oe_bare(&ArgParser::argShowEncryptionKey);
  494 + (*t)["check-linearization"] = oe_bare(&ArgParser::argCheckLinearization);
  495 + (*t)["show-linearization"] = oe_bare(&ArgParser::argShowLinearization);
  496 + (*t)["show-xref"] = oe_bare(&ArgParser::argShowXref);
  497 + (*t)["show-object"] = oe_requiredParameter(
478 498 &ArgParser::argShowObject, "obj[,gen]");
479   - t["raw-stream-data"] = oe_bare(&ArgParser::argShowObject);
480   - t["filtered-stream-data"] = oe_bare(&ArgParser::argFilteredStreamData);
481   - t["show-npages"] = oe_bare(&ArgParser::argShowNpages);
482   - t["show-pages"] = oe_bare(&ArgParser::argShowPages);
483   - t["with-images"] = oe_bare(&ArgParser::argWithImages);
484   - t["show-json"] = oe_bare(&ArgParser::argShowJson);
485   - t["check"] = oe_bare(&ArgParser::argCheck);
  499 + (*t)["raw-stream-data"] = oe_bare(&ArgParser::argShowObject);
  500 + (*t)["filtered-stream-data"] = oe_bare(&ArgParser::argFilteredStreamData);
  501 + (*t)["show-npages"] = oe_bare(&ArgParser::argShowNpages);
  502 + (*t)["show-pages"] = oe_bare(&ArgParser::argShowPages);
  503 + (*t)["with-images"] = oe_bare(&ArgParser::argWithImages);
  504 + (*t)["show-json"] = oe_bare(&ArgParser::argShowJson);
  505 + (*t)["check"] = oe_bare(&ArgParser::argCheck);
  506 +
  507 + t = &this->encrypt40_option_table;
  508 + (*t)["--"] = oe_bare(&ArgParser::argEndEncrypt);
  509 + (*t)["print"] = oe_requiredChoices(&ArgParser::arg40Print, yn);
  510 + (*t)["modify"] = oe_requiredChoices(&ArgParser::arg40Modify, yn);
  511 + (*t)["extract"] = oe_requiredChoices(&ArgParser::arg40Extract, yn);
  512 + (*t)["annotate"] = oe_requiredChoices(&ArgParser::arg40Annotate, yn);
  513 +
  514 + t = &this->encrypt128_option_table;
  515 + (*t)["--"] = oe_bare(&ArgParser::argEndEncrypt);
  516 + (*t)["accessibility"] = oe_requiredChoices(
  517 + &ArgParser::arg128Accessibility, yn);
  518 + (*t)["extract"] = oe_requiredChoices(&ArgParser::arg128Extract, yn);
  519 + char const* print128Choices[] = {"full", "low", "none", 0};
  520 + (*t)["print"] = oe_requiredChoices(
  521 + &ArgParser::arg128Print, print128Choices);
  522 + char const* modify128Choices[] =
  523 + {"all", "annotate", "form", "assembly", "none", 0};
  524 + (*t)["modify"] = oe_requiredChoices(
  525 + &ArgParser::arg128Modify, modify128Choices);
  526 + (*t)["cleartext-metadata"] = oe_bare(&ArgParser::arg128ClearTextMetadata);
  527 + // The above 128-bit options are also 256-bit options, so copy
  528 + // what we have so far. Then continue separately with 128 and 256.
  529 + this->encrypt256_option_table = this->encrypt128_option_table;
  530 + (*t)["use-aes"] = oe_requiredChoices(&ArgParser::arg128UseAes, yn);
  531 + (*t)["force-V4"] = oe_bare(&ArgParser::arg128ForceV4);
  532 +
  533 + t = &this->encrypt256_option_table;
  534 + (*t)["force-R5"] = oe_bare(&ArgParser::arg256ForceR5);
486 535 }
487 536  
488 537 void
... ... @@ -524,10 +573,33 @@ void
524 573 ArgParser::argEncrypt()
525 574 {
526 575 ++cur_arg;
527   - parseEncryptOptions();
528   - o.encrypt = true;
529   - o.decrypt = false;
530   - o.copy_encryption = false;
  576 + if (cur_arg + 3 >= argc)
  577 + {
  578 + usage("insufficient arguments to --encrypt");
  579 + }
  580 + o.user_password = argv[cur_arg++];
  581 + o.owner_password = argv[cur_arg++];
  582 + std::string len_str = argv[cur_arg];
  583 + if (len_str == "40")
  584 + {
  585 + o.keylen = 40;
  586 + this->option_table = &(this->encrypt40_option_table);
  587 + }
  588 + else if (len_str == "128")
  589 + {
  590 + o.keylen = 128;
  591 + this->option_table = &(this->encrypt128_option_table);
  592 + }
  593 + else if (len_str == "256")
  594 + {
  595 + o.keylen = 256;
  596 + o.use_aes = true;
  597 + this->option_table = &(this->encrypt256_option_table);
  598 + }
  599 + else
  600 + {
  601 + usage("encryption key length must be 40, 128, or 256");
  602 + }
531 603 }
532 604  
533 605 void
... ... @@ -878,6 +950,125 @@ ArgParser::argCheck()
878 950 }
879 951  
880 952 void
  953 +ArgParser::arg40Print(char* parameter)
  954 +{
  955 + o.r2_print = (strcmp(parameter, "y") == 0);
  956 +}
  957 +
  958 +void
  959 +ArgParser::arg40Modify(char* parameter)
  960 +{
  961 + o.r2_modify = (strcmp(parameter, "y") == 0);
  962 +}
  963 +
  964 +void
  965 +ArgParser::arg40Extract(char* parameter)
  966 +{
  967 + o.r2_extract = (strcmp(parameter, "y") == 0);
  968 +}
  969 +
  970 +void
  971 +ArgParser::arg40Annotate(char* parameter)
  972 +{
  973 + o.r2_annotate = (strcmp(parameter, "y") == 0);
  974 +}
  975 +
  976 +void
  977 +ArgParser::arg128Accessibility(char* parameter)
  978 +{
  979 + o.r3_accessibility = (strcmp(parameter, "y") == 0);
  980 +}
  981 +
  982 +void
  983 +ArgParser::arg128Extract(char* parameter)
  984 +{
  985 + o.r3_extract = (strcmp(parameter, "y") == 0);
  986 +}
  987 +
  988 +void
  989 +ArgParser::arg128Print(char* parameter)
  990 +{
  991 + if (strcmp(parameter, "full") == 0)
  992 + {
  993 + o.r3_print = qpdf_r3p_full;
  994 + }
  995 + else if (strcmp(parameter, "low") == 0)
  996 + {
  997 + o.r3_print = qpdf_r3p_low;
  998 + }
  999 + else if (strcmp(parameter, "none") == 0)
  1000 + {
  1001 + o.r3_print = qpdf_r3p_none;
  1002 + }
  1003 + else
  1004 + {
  1005 + usage("invalid print option");
  1006 + }
  1007 +}
  1008 +
  1009 +void
  1010 +ArgParser::arg128Modify(char* parameter)
  1011 +{
  1012 + if (strcmp(parameter, "all") == 0)
  1013 + {
  1014 + o.r3_modify = qpdf_r3m_all;
  1015 + }
  1016 + else if (strcmp(parameter, "annotate") == 0)
  1017 + {
  1018 + o.r3_modify = qpdf_r3m_annotate;
  1019 + }
  1020 + else if (strcmp(parameter, "form") == 0)
  1021 + {
  1022 + o.r3_modify = qpdf_r3m_form;
  1023 + }
  1024 + else if (strcmp(parameter, "assembly") == 0)
  1025 + {
  1026 + o.r3_modify = qpdf_r3m_assembly;
  1027 + }
  1028 + else if (strcmp(parameter, "none") == 0)
  1029 + {
  1030 + o.r3_modify = qpdf_r3m_none;
  1031 + }
  1032 + else
  1033 + {
  1034 + usage("invalid modify option");
  1035 + }
  1036 +}
  1037 +
  1038 +void
  1039 +ArgParser::arg128ClearTextMetadata()
  1040 +{
  1041 + o.cleartext_metadata = true;
  1042 +}
  1043 +
  1044 +void
  1045 +ArgParser::arg128UseAes(char* parameter)
  1046 +{
  1047 + o.use_aes = (strcmp(parameter, "y") == 0);
  1048 +}
  1049 +
  1050 +void
  1051 +ArgParser::arg128ForceV4()
  1052 +{
  1053 + o.force_V4 = true;
  1054 +}
  1055 +
  1056 +void
  1057 +ArgParser::arg256ForceR5()
  1058 +{
  1059 + o.force_R5 = true;
  1060 +}
  1061 +
  1062 +void
  1063 +ArgParser::argEndEncrypt()
  1064 +{
  1065 + o.encrypt = true;
  1066 + o.decrypt = false;
  1067 + o.copy_encryption = false;
  1068 + this->option_table = &(this->main_option_table);
  1069 +}
  1070 +
  1071 +void
881 1072 ArgParser::handleArgFileArguments()
882 1073 {
883 1074 // Support reading arguments from files. Create a new argv. Ensure
... ... @@ -1400,329 +1591,6 @@ ArgParser::parseNumrange(char const* range, int max, bool throw_error)
1400 1591 return std::vector<int>();
1401 1592 }
1402 1593  
1403   -void
1404   -ArgParser::parseEncryptOptions()
1405   -{
1406   - if (cur_arg + 3 >= argc)
1407   - {
1408   - usage("insufficient arguments to --encrypt");
1409   - }
1410   - o.user_password = argv[cur_arg++];
1411   - o.owner_password = argv[cur_arg++];
1412   - std::string len_str = argv[cur_arg++];
1413   - if (len_str == "40")
1414   - {
1415   - o.keylen = 40;
1416   - }
1417   - else if (len_str == "128")
1418   - {
1419   - o.keylen = 128;
1420   - }
1421   - else if (len_str == "256")
1422   - {
1423   - o.keylen = 256;
1424   - o.use_aes = true;
1425   - }
1426   - else
1427   - {
1428   - usage("encryption key length must be 40, 128, or 256");
1429   - }
1430   - while (1)
1431   - {
1432   - char* arg = argv[cur_arg];
1433   - if (arg == 0)
1434   - {
1435   - usage("insufficient arguments to --encrypt");
1436   - }
1437   - else if (strcmp(arg, "--") == 0)
1438   - {
1439   - return;
1440   - }
1441   - if (arg[0] == '-')
1442   - {
1443   - ++arg;
1444   - if (arg[0] == '-')
1445   - {
1446   - ++arg;
1447   - }
1448   - }
1449   - else
1450   - {
1451   - usage(std::string("invalid encryption parameter ") + arg);
1452   - }
1453   - ++cur_arg;
1454   - char* parameter = strchr(arg, '=');
1455   - if (parameter)
1456   - {
1457   - *parameter++ = 0;
1458   - }
1459   - if (strcmp(arg, "print") == 0)
1460   - {
1461   - if (parameter == 0)
1462   - {
1463   - usage("--print must be given as --print=option");
1464   - }
1465   - std::string val = parameter;
1466   - if (o.keylen == 40)
1467   - {
1468   - if (val == "y")
1469   - {
1470   - o.r2_print = true;
1471   - }
1472   - else if (val == "n")
1473   - {
1474   - o.r2_print = false;
1475   - }
1476   - else
1477   - {
1478   - usage("invalid 40-bit -print parameter");
1479   - }
1480   - }
1481   - else
1482   - {
1483   - if (val == "full")
1484   - {
1485   - o.r3_print = qpdf_r3p_full;
1486   - }
1487   - else if (val == "low")
1488   - {
1489   - o.r3_print = qpdf_r3p_low;
1490   - }
1491   - else if (val == "none")
1492   - {
1493   - o.r3_print = qpdf_r3p_none;
1494   - }
1495   - else
1496   - {
1497   - usage("invalid 128-bit -print parameter");
1498   - }
1499   - }
1500   - }
1501   - else if (strcmp(arg, "modify") == 0)
1502   - {
1503   - if (parameter == 0)
1504   - {
1505   - usage("--modify must be given as --modify=option");
1506   - }
1507   - std::string val = parameter;
1508   - if (o.keylen == 40)
1509   - {
1510   - if (val == "y")
1511   - {
1512   - o.r2_modify = true;
1513   - }
1514   - else if (val == "n")
1515   - {
1516   - o.r2_modify = false;
1517   - }
1518   - else
1519   - {
1520   - usage("invalid 40-bit -modify parameter");
1521   - }
1522   - }
1523   - else
1524   - {
1525   - if (val == "all")
1526   - {
1527   - o.r3_modify = qpdf_r3m_all;
1528   - }
1529   - else if (val == "annotate")
1530   - {
1531   - o.r3_modify = qpdf_r3m_annotate;
1532   - }
1533   - else if (val == "form")
1534   - {
1535   - o.r3_modify = qpdf_r3m_form;
1536   - }
1537   - else if (val == "assembly")
1538   - {
1539   - o.r3_modify = qpdf_r3m_assembly;
1540   - }
1541   - else if (val == "none")
1542   - {
1543   - o.r3_modify = qpdf_r3m_none;
1544   - }
1545   - else
1546   - {
1547   - usage("invalid 128-bit -modify parameter");
1548   - }
1549   - }
1550   - }
1551   - else if (strcmp(arg, "extract") == 0)
1552   - {
1553   - if (parameter == 0)
1554   - {
1555   - usage("--extract must be given as --extract=option");
1556   - }
1557   - std::string val = parameter;
1558   - bool result = false;
1559   - if (val == "y")
1560   - {
1561   - result = true;
1562   - }
1563   - else if (val == "n")
1564   - {
1565   - result = false;
1566   - }
1567   - else
1568   - {
1569   - usage("invalid -extract parameter");
1570   - }
1571   - if (o.keylen == 40)
1572   - {
1573   - o.r2_extract = result;
1574   - }
1575   - else
1576   - {
1577   - o.r3_extract = result;
1578   - }
1579   - }
1580   - else if (strcmp(arg, "annotate") == 0)
1581   - {
1582   - if (parameter == 0)
1583   - {
1584   - usage("--annotate must be given as --annotate=option");
1585   - }
1586   - std::string val = parameter;
1587   - bool result = false;
1588   - if (val == "y")
1589   - {
1590   - result = true;
1591   - }
1592   - else if (val == "n")
1593   - {
1594   - result = false;
1595   - }
1596   - else
1597   - {
1598   - usage("invalid -annotate parameter");
1599   - }
1600   - if (o.keylen == 40)
1601   - {
1602   - o.r2_annotate = result;
1603   - }
1604   - else
1605   - {
1606   - usage("-annotate invalid for 128-bit keys");
1607   - }
1608   - }
1609   - else if (strcmp(arg, "accessibility") == 0)
1610   - {
1611   - if (parameter == 0)
1612   - {
1613   - usage("--accessibility must be given as"
1614   - " --accessibility=option");
1615   - }
1616   - std::string val = parameter;
1617   - bool result = false;
1618   - if (val == "y")
1619   - {
1620   - result = true;
1621   - }
1622   - else if (val == "n")
1623   - {
1624   - result = false;
1625   - }
1626   - else
1627   - {
1628   - usage("invalid -accessibility parameter");
1629   - }
1630   - if (o.keylen == 40)
1631   - {
1632   - usage("-accessibility invalid for 40-bit keys");
1633   - }
1634   - else
1635   - {
1636   - o.r3_accessibility = result;
1637   - }
1638   - }
1639   - else if (strcmp(arg, "cleartext-metadata") == 0)
1640   - {
1641   - if (parameter)
1642   - {
1643   - usage("--cleartext-metadata does not take a parameter");
1644   - }
1645   - if (o.keylen == 40)
1646   - {
1647   - usage("--cleartext-metadata is invalid for 40-bit keys");
1648   - }
1649   - else
1650   - {
1651   - o.cleartext_metadata = true;
1652   - }
1653   - }
1654   - else if (strcmp(arg, "force-V4") == 0)
1655   - {
1656   - if (parameter)
1657   - {
1658   - usage("--force-V4 does not take a parameter");
1659   - }
1660   - if (o.keylen != 128)
1661   - {
1662   - usage("--force-V4 is invalid only for 128-bit keys");
1663   - }
1664   - else
1665   - {
1666   - o.force_V4 = true;
1667   - }
1668   - }
1669   - else if (strcmp(arg, "force-R5") == 0)
1670   - {
1671   - if (parameter)
1672   - {
1673   - usage("--force-R5 does not take a parameter");
1674   - }
1675   - if (o.keylen != 256)
1676   - {
1677   - usage("--force-R5 is invalid only for 256-bit keys");
1678   - }
1679   - else
1680   - {
1681   - o.force_R5 = true;
1682   - }
1683   - }
1684   - else if (strcmp(arg, "use-aes") == 0)
1685   - {
1686   - if (parameter == 0)
1687   - {
1688   - usage("--use-aes must be given as --extract=option");
1689   - }
1690   - std::string val = parameter;
1691   - bool result = false;
1692   - if (val == "y")
1693   - {
1694   - result = true;
1695   - }
1696   - else if (val == "n")
1697   - {
1698   - result = false;
1699   - }
1700   - else
1701   - {
1702   - usage("invalid -use-aes parameter");
1703   - }
1704   - if ((o.keylen == 40) && result)
1705   - {
1706   - usage("use-aes is invalid for 40-bit keys");
1707   - }
1708   - else if ((o.keylen == 256) && (! result))
1709   - {
1710   - // qpdf would happily create files encrypted with RC4
1711   - // using /V=5, but Adobe reader can't read them.
1712   - usage("use-aes can't be disabled with 256-bit keys");
1713   - }
1714   - else
1715   - {
1716   - o.use_aes = result;
1717   - }
1718   - }
1719   - else
1720   - {
1721   - usage(std::string("invalid encryption parameter --") + arg);
1722   - }
1723   - }
1724   -}
1725   -
1726 1594 std::vector<PageSpec>
1727 1595 ArgParser::parsePagesOptions()
1728 1596 {
... ... @@ -1990,7 +1858,17 @@ ArgParser::parseOptions()
1990 1858 for (cur_arg = 1; cur_arg < argc; ++cur_arg)
1991 1859 {
1992 1860 char* arg = argv[cur_arg];
1993   - if ((arg[0] == '-') && (strcmp(arg, "-") != 0))
  1861 + if (strcmp(arg, "--") == 0)
  1862 + {
  1863 + // Special case for -- option, which is used to break out
  1864 + // of subparsers.
  1865 + OptionEntry& oe = (*this->option_table)["--"];
  1866 + if (oe.bare_arg_handler)
  1867 + {
  1868 + (this->*(oe.bare_arg_handler))();
  1869 + }
  1870 + }
  1871 + else if ((arg[0] == '-') && (strcmp(arg, "-") != 0))
1994 1872 {
1995 1873 ++arg;
1996 1874 if (arg[0] == '-')
... ... @@ -1998,19 +1876,28 @@ ArgParser::parseOptions()
1998 1876 // Be lax about -arg vs --arg
1999 1877 ++arg;
2000 1878 }
2001   - char* parameter = const_cast<char*>(strchr(arg, '='));
  1879 + char* parameter = 0;
  1880 + if (strlen(arg) > 0)
  1881 + {
  1882 + // Prevent --=something from being treated as an empty
  1883 + // arg since the empty string in the option table is
  1884 + // for positional arguments.
  1885 + parameter = const_cast<char*>(strchr(1 + arg, '='));
  1886 + }
2002 1887 if (parameter)
2003 1888 {
2004 1889 *parameter++ = 0;
2005 1890 }
2006 1891  
2007 1892 std::string arg_s(arg);
2008   - if (0 == this->option_table.count(arg_s))
  1893 + if (arg_s.empty() ||
  1894 + (arg_s.at(0) == '-') ||
  1895 + (0 == this->option_table->count(arg_s)))
2009 1896 {
2010 1897 usage(std::string("unknown option --") + arg);
2011 1898 }
2012 1899  
2013   - OptionEntry& oe = this->option_table[arg_s];
  1900 + OptionEntry& oe = (*this->option_table)[arg_s];
2014 1901 if ((oe.parameter_needed && (0 == parameter)) ||
2015 1902 ((! oe.choices.empty() &&
2016 1903 ((0 == parameter) ||
... ... @@ -2055,9 +1942,11 @@ ArgParser::parseOptions()
2055 1942 (this->*(oe.param_arg_handler))(parameter);
2056 1943 }
2057 1944 }
2058   - else if (0 != this->option_table.count(""))
  1945 + else if (0 != this->option_table->count(""))
2059 1946 {
2060   - OptionEntry& oe = this->option_table[""];
  1947 + // The empty string maps to the positional argument
  1948 + // handler.
  1949 + OptionEntry& oe = (*this->option_table)[""];
2061 1950 if (oe.param_arg_handler)
2062 1951 {
2063 1952 (this->*(oe.param_arg_handler))(arg);
... ... @@ -2069,6 +1958,10 @@ ArgParser::parseOptions()
2069 1958 }
2070 1959 }
2071 1960  
  1961 + if (this->option_table != &(this->main_option_table))
  1962 + {
  1963 + usage("missing -- at end of options");
  1964 + }
2072 1965 if (o.infilename == 0)
2073 1966 {
2074 1967 usage("an input file name is required");
... ...