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,13 +329,25 @@ class ArgParser
329 void argWithImages(); 329 void argWithImages();
330 void argShowJson(); 330 void argShowJson();
331 void argCheck(); 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 void usage(std::string const& message); 346 void usage(std::string const& message);
334 void initOptionTable(); 347 void initOptionTable();
335 void handleHelpVersion(); 348 void handleHelpVersion();
336 void handleArgFileArguments(); 349 void handleArgFileArguments();
337 void readArgsFromFile(char const* filename); 350 void readArgsFromFile(char const* filename);
338 - void parseEncryptOptions();  
339 std::vector<PageSpec> parsePagesOptions(); 351 std::vector<PageSpec> parsePagesOptions();
340 void parseRotationParameter(std::string const&); 352 void parseRotationParameter(std::string const&);
341 std::vector<int> parseNumrange(char const* range, int max, 353 std::vector<int> parseNumrange(char const* range, int max,
@@ -348,7 +360,11 @@ class ArgParser @@ -348,7 +360,11 @@ class ArgParser
348 Options& o; 360 Options& o;
349 int cur_arg; 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 std::vector<PointerHolder<char> > new_argv; 368 std::vector<PointerHolder<char> > new_argv;
353 PointerHolder<char*> argv_ph; 369 PointerHolder<char*> argv_ph;
354 }; 370 };
@@ -359,6 +375,7 @@ ArgParser::ArgParser(int argc, char* argv[], Options&amp; o) : @@ -359,6 +375,7 @@ ArgParser::ArgParser(int argc, char* argv[], Options&amp; o) :
359 o(o), 375 o(o),
360 cur_arg(0) 376 cur_arg(0)
361 { 377 {
  378 + option_table = &main_option_table;
362 initOptionTable(); 379 initOptionTable();
363 } 380 }
364 381
@@ -414,75 +431,107 @@ ArgParser::oe_requiredChoices(param_arg_handler_t h, char const** choices) @@ -414,75 +431,107 @@ ArgParser::oe_requiredChoices(param_arg_handler_t h, char const** choices)
414 void 431 void
415 ArgParser::initOptionTable() 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 char const* yn[] = {"y", "n", 0}; 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 &ArgParser::argCopyEncryption, "file"); 444 &ArgParser::argCopyEncryption, "file");
428 - t["encryption-file-password"] = oe_requiredParameter( 445 + (*t)["encryption-file-password"] = oe_requiredParameter(
429 &ArgParser::argEncryptionFilePassword, "password"); 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 &ArgParser::argRotate, "[+|-]angle:page-range"); 449 &ArgParser::argRotate, "[+|-]angle:page-range");
433 char const* streamDataChoices[] = 450 char const* streamDataChoices[] =
434 {"compress", "preserve", "uncompress", 0}; 451 {"compress", "preserve", "uncompress", 0};
435 - t["stream-data"] = oe_requiredChoices( 452 + (*t)["stream-data"] = oe_requiredChoices(
436 &ArgParser::argStreamData, streamDataChoices); 453 &ArgParser::argStreamData, streamDataChoices);
437 - t["compress-streams"] = oe_requiredChoices( 454 + (*t)["compress-streams"] = oe_requiredChoices(
438 &ArgParser::argCompressStreams, yn); 455 &ArgParser::argCompressStreams, yn);
439 char const* decodeLevelChoices[] = 456 char const* decodeLevelChoices[] =
440 {"none", "generalized", "specialized", "all", 0}; 457 {"none", "generalized", "specialized", "all", 0};
441 - t["decode-level"] = oe_requiredChoices( 458 + (*t)["decode-level"] = oe_requiredChoices(
442 &ArgParser::argDecodeLevel, decodeLevelChoices); 459 &ArgParser::argDecodeLevel, decodeLevelChoices);
443 - t["normalize-content"] = oe_requiredChoices( 460 + (*t)["normalize-content"] = oe_requiredChoices(
444 &ArgParser::argNormalizeContent, yn); 461 &ArgParser::argNormalizeContent, yn);
445 - t["suppress-recovery"] = oe_bare(&ArgParser::argSuppressRecovery); 462 + (*t)["suppress-recovery"] = oe_bare(&ArgParser::argSuppressRecovery);
446 char const* objectStreamsChoices[] = {"disable", "preserve", "generate", 0}; 463 char const* objectStreamsChoices[] = {"disable", "preserve", "generate", 0};
447 - t["object-streams"] = oe_requiredChoices( 464 + (*t)["object-streams"] = oe_requiredChoices(
448 &ArgParser::argObjectStreams, objectStreamsChoices); 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 &ArgParser::argPreserveUnreferencedResources); 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 &ArgParser::argNewlineBeforeEndstream); 475 &ArgParser::argNewlineBeforeEndstream);
457 - t["linearize-pass1"] = oe_requiredParameter( 476 + (*t)["linearize-pass1"] = oe_requiredParameter(
458 &ArgParser::argLinearizePass1, "filename"); 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 &ArgParser::argMinVersion, "version"); 480 &ArgParser::argMinVersion, "version");
462 - t["force-version"] = oe_requiredParameter( 481 + (*t)["force-version"] = oe_requiredParameter(
463 &ArgParser::argForceVersion, "version"); 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 &ArgParser::argShowObject, "obj[,gen]"); 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 void 537 void
@@ -524,10 +573,33 @@ void @@ -524,10 +573,33 @@ void
524 ArgParser::argEncrypt() 573 ArgParser::argEncrypt()
525 { 574 {
526 ++cur_arg; 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 void 605 void
@@ -878,6 +950,125 @@ ArgParser::argCheck() @@ -878,6 +950,125 @@ ArgParser::argCheck()
878 } 950 }
879 951
880 void 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 ArgParser::handleArgFileArguments() 1072 ArgParser::handleArgFileArguments()
882 { 1073 {
883 // Support reading arguments from files. Create a new argv. Ensure 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,329 +1591,6 @@ ArgParser::parseNumrange(char const* range, int max, bool throw_error)
1400 return std::vector<int>(); 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 std::vector<PageSpec> 1594 std::vector<PageSpec>
1727 ArgParser::parsePagesOptions() 1595 ArgParser::parsePagesOptions()
1728 { 1596 {
@@ -1990,7 +1858,17 @@ ArgParser::parseOptions() @@ -1990,7 +1858,17 @@ ArgParser::parseOptions()
1990 for (cur_arg = 1; cur_arg < argc; ++cur_arg) 1858 for (cur_arg = 1; cur_arg < argc; ++cur_arg)
1991 { 1859 {
1992 char* arg = argv[cur_arg]; 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 ++arg; 1873 ++arg;
1996 if (arg[0] == '-') 1874 if (arg[0] == '-')
@@ -1998,19 +1876,28 @@ ArgParser::parseOptions() @@ -1998,19 +1876,28 @@ ArgParser::parseOptions()
1998 // Be lax about -arg vs --arg 1876 // Be lax about -arg vs --arg
1999 ++arg; 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 if (parameter) 1887 if (parameter)
2003 { 1888 {
2004 *parameter++ = 0; 1889 *parameter++ = 0;
2005 } 1890 }
2006 1891
2007 std::string arg_s(arg); 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 usage(std::string("unknown option --") + arg); 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 if ((oe.parameter_needed && (0 == parameter)) || 1901 if ((oe.parameter_needed && (0 == parameter)) ||
2015 ((! oe.choices.empty() && 1902 ((! oe.choices.empty() &&
2016 ((0 == parameter) || 1903 ((0 == parameter) ||
@@ -2055,9 +1942,11 @@ ArgParser::parseOptions() @@ -2055,9 +1942,11 @@ ArgParser::parseOptions()
2055 (this->*(oe.param_arg_handler))(parameter); 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 if (oe.param_arg_handler) 1950 if (oe.param_arg_handler)
2062 { 1951 {
2063 (this->*(oe.param_arg_handler))(arg); 1952 (this->*(oe.param_arg_handler))(arg);
@@ -2069,6 +1958,10 @@ ArgParser::parseOptions() @@ -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 if (o.infilename == 0) 1965 if (o.infilename == 0)
2073 { 1966 {
2074 usage("an input file name is required"); 1967 usage("an input file name is required");