Commit 21b9290785fb03477784cf6312f57cfb96dbe53d
1 parent
ea96330b
QPDFJob json: make bare arguments expect the empty string
Changing from bool requiring true to string requiring the empty string is more consistent with the CLI and makes it possible to add an optional parameter or choices later without breaking compatibility.
Showing
21 changed files
with
89 additions
and
77 deletions
generate_auto_job
| ... | ... | @@ -465,14 +465,19 @@ class Main: |
| 465 | 465 | self.json_init.append( |
| 466 | 466 | f'addBare([this]() {{ {config}->{flag_key}(); }});') |
| 467 | 467 | elif kind == 'optional_parameter' or kind == 'required_parameter': |
| 468 | - # No optional parameters in json | |
| 468 | + # Optional parameters end up just being the empty string, | |
| 469 | + # so the handler has to deal with it. The empty string is | |
| 470 | + # also allowed for non-optional. | |
| 469 | 471 | self.json_init.append( |
| 470 | 472 | f'addParameter([this](char const* p)' |
| 471 | 473 | f' {{ {config}->{flag_key}(p); }});') |
| 472 | - elif kind == 'optional_choices' or kind == 'required_choices': | |
| 473 | - # No optional choices in json | |
| 474 | + elif kind == 'optional_choices': | |
| 475 | + self.json_init.append( | |
| 476 | + f'addChoices({v}_choices, false,' | |
| 477 | + f' [this](char const* p) {{ {config}->{flag_key}(p); }});') | |
| 478 | + elif kind == 'required_choices': | |
| 474 | 479 | self.json_init.append( |
| 475 | - f'addChoices({v}_choices,' | |
| 480 | + f'addChoices({v}_choices, true,' | |
| 476 | 481 | f' [this](char const* p) {{ {config}->{flag_key}(p); }});') |
| 477 | 482 | |
| 478 | 483 | def handle_json_manual(self, path): | ... | ... |
job.sums
| 1 | 1 | # Generated by generate_auto_job |
| 2 | -generate_auto_job 905fed38c06d258af617ac909bed78a7888a5eaba3f14cf143168665f6e90a86 | |
| 2 | +generate_auto_job 8b3cc47eb96bfd003954d16d51c482e0e015544fdcdc1cbc89b6dcd964f8a2cb | |
| 3 | 3 | include/qpdf/auto_job_c_att.hh 7ad43bb374c1370ef32ebdcdcb7b73a61d281f7f4e3f12755585872ab30fb60e |
| 4 | 4 | include/qpdf/auto_job_c_copy_att.hh 32275d03cdc69b703dd7e02ba0bbe15756e714e9ad185484773a6178dc09e1ee |
| 5 | 5 | include/qpdf/auto_job_c_enc.hh 72e138c7b96ed5aacdce78c1dec04b1c20d361faec4f8faf52f64c1d6be99265 |
| ... | ... | @@ -11,7 +11,7 @@ libqpdf/qpdf/auto_job_decl.hh 9f79396ec459f191be4c5fe34cf88c265cf47355a1a945fa39 |
| 11 | 11 | libqpdf/qpdf/auto_job_help.hh a0ab6ab4dde2ad3d3f17ecae3ea274919119329e075061f3a3973535f5e367de |
| 12 | 12 | libqpdf/qpdf/auto_job_init.hh c244e03e8b83ed7db732920f40aff0134e5f2e78a6edb9473ea4dd1934a8953e |
| 13 | 13 | libqpdf/qpdf/auto_job_json_decl.hh c5e3fd38a3b0c569eb0c6b4c60953a09cd6bc7d3361a357a81f64fe36af2b0cf |
| 14 | -libqpdf/qpdf/auto_job_json_init.hh bfaf88ad1461e1157e7a0eb6e8c90669eba6d03b5b1ffd2e7e7041250c5f0523 | |
| 14 | +libqpdf/qpdf/auto_job_json_init.hh 3f86ce40931ca8f417d050fcd49104d73c1fa4e977ad19d54b372831a8ea17ed | |
| 15 | 15 | libqpdf/qpdf/auto_job_schema.hh 2ec70dffdd15974d74102b4d7ada9f97449bc28c98be119efee5e15507ed22a8 |
| 16 | 16 | manual/_ext/qpdf.py e9ac9d6c70642a3d29281ee5ad92ae2422dee8be9306fb8a0bc9dba0ed5e28f3 |
| 17 | 17 | manual/cli.rst a75a7e34aa9aba4f06e9c88cae9a2d9a2aa4e55a08521dde1478e8f2d80aadab | ... | ... |
libqpdf/QPDFJob_config.cc
| ... | ... | @@ -108,7 +108,7 @@ QPDFJob::Config::coalesceContents() |
| 108 | 108 | QPDFJob::Config* |
| 109 | 109 | QPDFJob::Config::collate(char const* parameter) |
| 110 | 110 | { |
| 111 | - auto n = ((parameter == 0) ? 1 : | |
| 111 | + auto n = (((parameter == 0) || (strlen(parameter) == 0)) ? 1 : | |
| 112 | 112 | QUtil::string_to_uint(parameter)); |
| 113 | 113 | o.m->collate = QIntC::to_size(n); |
| 114 | 114 | return this; |
| ... | ... | @@ -519,7 +519,7 @@ QPDFJob::Config::showXref() |
| 519 | 519 | QPDFJob::Config* |
| 520 | 520 | QPDFJob::Config::splitPages(char const* parameter) |
| 521 | 521 | { |
| 522 | - int n = ((parameter == 0) ? 1 : | |
| 522 | + int n = (((parameter == 0) || (strlen(parameter) == 0)) ? 1 : | |
| 523 | 523 | QUtil::string_to_int(parameter)); |
| 524 | 524 | o.m->split_pages = n; |
| 525 | 525 | return this; | ... | ... |
libqpdf/QPDFJob_json.cc
| ... | ... | @@ -31,7 +31,7 @@ namespace |
| 31 | 31 | |
| 32 | 32 | void addBare(bare_handler_t); |
| 33 | 33 | void addParameter(param_handler_t); |
| 34 | - void addChoices(char const** choices, param_handler_t); | |
| 34 | + void addChoices(char const** choices, bool required, param_handler_t); | |
| 35 | 35 | void pushKey(std::string const& key); |
| 36 | 36 | void beginDict(json_handler_t start_fn, |
| 37 | 37 | bare_handler_t end_fn); |
| ... | ... | @@ -106,11 +106,12 @@ Handlers::initHandlers() |
| 106 | 106 | void |
| 107 | 107 | Handlers::addBare(bare_handler_t fn) |
| 108 | 108 | { |
| 109 | - jh->addBoolHandler([this, fn](std::string const& path, bool v){ | |
| 110 | - if (! v) | |
| 109 | + jh->addStringHandler( | |
| 110 | + [this, fn](std::string const& path, std::string const& parameter){ | |
| 111 | + if (! parameter.empty()) | |
| 111 | 112 | { |
| 112 | - QTC::TC("qpdf", "QPDFJob json bare not true"); | |
| 113 | - usage(path + ": value must be true"); | |
| 113 | + QTC::TC("qpdf", "QPDFJob json bare not empty"); | |
| 114 | + usage(path + ": value must be the empty string"); | |
| 114 | 115 | } |
| 115 | 116 | else |
| 116 | 117 | { |
| ... | ... | @@ -129,22 +130,28 @@ Handlers::addParameter(param_handler_t fn) |
| 129 | 130 | } |
| 130 | 131 | |
| 131 | 132 | void |
| 132 | -Handlers::addChoices(char const** choices, | |
| 133 | - param_handler_t fn) | |
| 133 | +Handlers::addChoices(char const** choices, bool required, param_handler_t fn) | |
| 134 | 134 | { |
| 135 | 135 | jh->addStringHandler( |
| 136 | - [fn, choices, this]( | |
| 136 | + [fn, choices, required, this]( | |
| 137 | 137 | std::string const& path, std::string const& parameter){ |
| 138 | 138 | |
| 139 | 139 | char const* p = parameter.c_str(); |
| 140 | 140 | bool matches = false; |
| 141 | - for (char const** i = choices; *i; ++i) | |
| 141 | + if ((! required) && (parameter.empty())) | |
| 142 | + { | |
| 143 | + matches = true; | |
| 144 | + } | |
| 145 | + if (! matches) | |
| 142 | 146 | { |
| 143 | - if (strcmp(*i, p) == 0) | |
| 147 | + for (char const** i = choices; *i; ++i) | |
| 144 | 148 | { |
| 145 | - QTC::TC("qpdf", "QPDFJob json choice match"); | |
| 146 | - matches = true; | |
| 147 | - break; | |
| 149 | + if (strcmp(*i, p) == 0) | |
| 150 | + { | |
| 151 | + QTC::TC("qpdf", "QPDFJob json choice match"); | |
| 152 | + matches = true; | |
| 153 | + break; | |
| 154 | + } | |
| 148 | 155 | } |
| 149 | 156 | } |
| 150 | 157 | if (! matches) | ... | ... |
libqpdf/qpdf/auto_job_json_init.hh
| ... | ... | @@ -43,19 +43,19 @@ pushKey("newlineBeforeEndstream"); |
| 43 | 43 | addBare([this]() { c_main->newlineBeforeEndstream(); }); |
| 44 | 44 | popHandler(); // key: newlineBeforeEndstream |
| 45 | 45 | pushKey("normalizeContent"); |
| 46 | -addChoices(yn_choices, [this](char const* p) { c_main->normalizeContent(p); }); | |
| 46 | +addChoices(yn_choices, true, [this](char const* p) { c_main->normalizeContent(p); }); | |
| 47 | 47 | popHandler(); // key: normalizeContent |
| 48 | 48 | pushKey("streamData"); |
| 49 | -addChoices(stream_data_choices, [this](char const* p) { c_main->streamData(p); }); | |
| 49 | +addChoices(stream_data_choices, true, [this](char const* p) { c_main->streamData(p); }); | |
| 50 | 50 | popHandler(); // key: streamData |
| 51 | 51 | pushKey("compressStreams"); |
| 52 | -addChoices(yn_choices, [this](char const* p) { c_main->compressStreams(p); }); | |
| 52 | +addChoices(yn_choices, true, [this](char const* p) { c_main->compressStreams(p); }); | |
| 53 | 53 | popHandler(); // key: compressStreams |
| 54 | 54 | pushKey("recompressFlate"); |
| 55 | 55 | addBare([this]() { c_main->recompressFlate(); }); |
| 56 | 56 | popHandler(); // key: recompressFlate |
| 57 | 57 | pushKey("decodeLevel"); |
| 58 | -addChoices(decode_level_choices, [this](char const* p) { c_main->decodeLevel(p); }); | |
| 58 | +addChoices(decode_level_choices, true, [this](char const* p) { c_main->decodeLevel(p); }); | |
| 59 | 59 | popHandler(); // key: decodeLevel |
| 60 | 60 | pushKey("decrypt"); |
| 61 | 61 | addBare([this]() { c_main->decrypt(); }); |
| ... | ... | @@ -85,7 +85,7 @@ pushKey("linearizePass1"); |
| 85 | 85 | addParameter([this](char const* p) { c_main->linearizePass1(p); }); |
| 86 | 86 | popHandler(); // key: linearizePass1 |
| 87 | 87 | pushKey("objectStreams"); |
| 88 | -addChoices(object_streams_choices, [this](char const* p) { c_main->objectStreams(p); }); | |
| 88 | +addChoices(object_streams_choices, true, [this](char const* p) { c_main->objectStreams(p); }); | |
| 89 | 89 | popHandler(); // key: objectStreams |
| 90 | 90 | pushKey("minVersion"); |
| 91 | 91 | addParameter([this](char const* p) { c_main->minVersion(p); }); |
| ... | ... | @@ -110,82 +110,82 @@ popHandler(); // key: ownerPassword |
| 110 | 110 | pushKey("40bit"); |
| 111 | 111 | beginDict(bindJSON(&Handlers::beginEncrypt40bit), bindBare(&Handlers::endEncrypt40bit)); // .encrypt.40bit |
| 112 | 112 | pushKey("annotate"); |
| 113 | -addChoices(yn_choices, [this](char const* p) { c_enc->annotate(p); }); | |
| 113 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->annotate(p); }); | |
| 114 | 114 | popHandler(); // key: annotate |
| 115 | 115 | pushKey("extract"); |
| 116 | -addChoices(yn_choices, [this](char const* p) { c_enc->extract(p); }); | |
| 116 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->extract(p); }); | |
| 117 | 117 | popHandler(); // key: extract |
| 118 | 118 | pushKey("modify"); |
| 119 | -addChoices(modify128_choices, [this](char const* p) { c_enc->modify(p); }); | |
| 119 | +addChoices(modify128_choices, true, [this](char const* p) { c_enc->modify(p); }); | |
| 120 | 120 | popHandler(); // key: modify |
| 121 | 121 | pushKey("print"); |
| 122 | -addChoices(print128_choices, [this](char const* p) { c_enc->print(p); }); | |
| 122 | +addChoices(print128_choices, true, [this](char const* p) { c_enc->print(p); }); | |
| 123 | 123 | popHandler(); // key: print |
| 124 | 124 | popHandler(); // key: 40bit |
| 125 | 125 | pushKey("128bit"); |
| 126 | 126 | beginDict(bindJSON(&Handlers::beginEncrypt128bit), bindBare(&Handlers::endEncrypt128bit)); // .encrypt.128bit |
| 127 | 127 | pushKey("accessibility"); |
| 128 | -addChoices(yn_choices, [this](char const* p) { c_enc->accessibility(p); }); | |
| 128 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->accessibility(p); }); | |
| 129 | 129 | popHandler(); // key: accessibility |
| 130 | 130 | pushKey("annotate"); |
| 131 | -addChoices(yn_choices, [this](char const* p) { c_enc->annotate(p); }); | |
| 131 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->annotate(p); }); | |
| 132 | 132 | popHandler(); // key: annotate |
| 133 | 133 | pushKey("assemble"); |
| 134 | -addChoices(yn_choices, [this](char const* p) { c_enc->assemble(p); }); | |
| 134 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->assemble(p); }); | |
| 135 | 135 | popHandler(); // key: assemble |
| 136 | 136 | pushKey("cleartextMetadata"); |
| 137 | 137 | addBare([this]() { c_enc->cleartextMetadata(); }); |
| 138 | 138 | popHandler(); // key: cleartextMetadata |
| 139 | 139 | pushKey("extract"); |
| 140 | -addChoices(yn_choices, [this](char const* p) { c_enc->extract(p); }); | |
| 140 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->extract(p); }); | |
| 141 | 141 | popHandler(); // key: extract |
| 142 | 142 | pushKey("form"); |
| 143 | -addChoices(yn_choices, [this](char const* p) { c_enc->form(p); }); | |
| 143 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->form(p); }); | |
| 144 | 144 | popHandler(); // key: form |
| 145 | 145 | pushKey("modifyOther"); |
| 146 | -addChoices(yn_choices, [this](char const* p) { c_enc->modifyOther(p); }); | |
| 146 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->modifyOther(p); }); | |
| 147 | 147 | popHandler(); // key: modifyOther |
| 148 | 148 | pushKey("modify"); |
| 149 | -addChoices(modify128_choices, [this](char const* p) { c_enc->modify(p); }); | |
| 149 | +addChoices(modify128_choices, true, [this](char const* p) { c_enc->modify(p); }); | |
| 150 | 150 | popHandler(); // key: modify |
| 151 | 151 | pushKey("print"); |
| 152 | -addChoices(print128_choices, [this](char const* p) { c_enc->print(p); }); | |
| 152 | +addChoices(print128_choices, true, [this](char const* p) { c_enc->print(p); }); | |
| 153 | 153 | popHandler(); // key: print |
| 154 | 154 | pushKey("forceV4"); |
| 155 | 155 | addBare([this]() { c_enc->forceV4(); }); |
| 156 | 156 | popHandler(); // key: forceV4 |
| 157 | 157 | pushKey("useAes"); |
| 158 | -addChoices(yn_choices, [this](char const* p) { c_enc->useAes(p); }); | |
| 158 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->useAes(p); }); | |
| 159 | 159 | popHandler(); // key: useAes |
| 160 | 160 | popHandler(); // key: 128bit |
| 161 | 161 | pushKey("256bit"); |
| 162 | 162 | beginDict(bindJSON(&Handlers::beginEncrypt256bit), bindBare(&Handlers::endEncrypt256bit)); // .encrypt.256bit |
| 163 | 163 | pushKey("accessibility"); |
| 164 | -addChoices(yn_choices, [this](char const* p) { c_enc->accessibility(p); }); | |
| 164 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->accessibility(p); }); | |
| 165 | 165 | popHandler(); // key: accessibility |
| 166 | 166 | pushKey("annotate"); |
| 167 | -addChoices(yn_choices, [this](char const* p) { c_enc->annotate(p); }); | |
| 167 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->annotate(p); }); | |
| 168 | 168 | popHandler(); // key: annotate |
| 169 | 169 | pushKey("assemble"); |
| 170 | -addChoices(yn_choices, [this](char const* p) { c_enc->assemble(p); }); | |
| 170 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->assemble(p); }); | |
| 171 | 171 | popHandler(); // key: assemble |
| 172 | 172 | pushKey("cleartextMetadata"); |
| 173 | 173 | addBare([this]() { c_enc->cleartextMetadata(); }); |
| 174 | 174 | popHandler(); // key: cleartextMetadata |
| 175 | 175 | pushKey("extract"); |
| 176 | -addChoices(yn_choices, [this](char const* p) { c_enc->extract(p); }); | |
| 176 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->extract(p); }); | |
| 177 | 177 | popHandler(); // key: extract |
| 178 | 178 | pushKey("form"); |
| 179 | -addChoices(yn_choices, [this](char const* p) { c_enc->form(p); }); | |
| 179 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->form(p); }); | |
| 180 | 180 | popHandler(); // key: form |
| 181 | 181 | pushKey("modifyOther"); |
| 182 | -addChoices(yn_choices, [this](char const* p) { c_enc->modifyOther(p); }); | |
| 182 | +addChoices(yn_choices, true, [this](char const* p) { c_enc->modifyOther(p); }); | |
| 183 | 183 | popHandler(); // key: modifyOther |
| 184 | 184 | pushKey("modify"); |
| 185 | -addChoices(modify128_choices, [this](char const* p) { c_enc->modify(p); }); | |
| 185 | +addChoices(modify128_choices, true, [this](char const* p) { c_enc->modify(p); }); | |
| 186 | 186 | popHandler(); // key: modify |
| 187 | 187 | pushKey("print"); |
| 188 | -addChoices(print128_choices, [this](char const* p) { c_enc->print(p); }); | |
| 188 | +addChoices(print128_choices, true, [this](char const* p) { c_enc->print(p); }); | |
| 189 | 189 | popHandler(); // key: print |
| 190 | 190 | pushKey("allowInsecure"); |
| 191 | 191 | addBare([this]() { c_enc->allowInsecure(); }); |
| ... | ... | @@ -238,11 +238,11 @@ pushKey("showAttachment"); |
| 238 | 238 | addParameter([this](char const* p) { c_main->showAttachment(p); }); |
| 239 | 239 | popHandler(); // key: showAttachment |
| 240 | 240 | pushKey("json"); |
| 241 | -addChoices(json_version_choices, [this](char const* p) { c_main->json(p); }); | |
| 241 | +addChoices(json_version_choices, false, [this](char const* p) { c_main->json(p); }); | |
| 242 | 242 | popHandler(); // key: json |
| 243 | 243 | pushKey("jsonKey"); |
| 244 | 244 | beginArray(bindJSON(&Handlers::beginJsonKeyArray), bindBare(&Handlers::endJsonKeyArray)); // .jsonKey[] |
| 245 | -addChoices(json_key_choices, [this](char const* p) { c_main->jsonKey(p); }); | |
| 245 | +addChoices(json_key_choices, true, [this](char const* p) { c_main->jsonKey(p); }); | |
| 246 | 246 | popHandler(); // array: .jsonKey[] |
| 247 | 247 | popHandler(); // key: jsonKey |
| 248 | 248 | pushKey("jsonObject"); |
| ... | ... | @@ -254,7 +254,7 @@ pushKey("allowWeakCrypto"); |
| 254 | 254 | addBare([this]() { c_main->allowWeakCrypto(); }); |
| 255 | 255 | popHandler(); // key: allowWeakCrypto |
| 256 | 256 | pushKey("keepFilesOpen"); |
| 257 | -addChoices(yn_choices, [this](char const* p) { c_main->keepFilesOpen(p); }); | |
| 257 | +addChoices(yn_choices, true, [this](char const* p) { c_main->keepFilesOpen(p); }); | |
| 258 | 258 | popHandler(); // key: keepFilesOpen |
| 259 | 259 | pushKey("keepFilesOpenThreshold"); |
| 260 | 260 | addParameter([this](char const* p) { c_main->keepFilesOpenThreshold(p); }); |
| ... | ... | @@ -272,7 +272,7 @@ pushKey("passwordIsHexKey"); |
| 272 | 272 | addBare([this]() { c_main->passwordIsHexKey(); }); |
| 273 | 273 | popHandler(); // key: passwordIsHexKey |
| 274 | 274 | pushKey("passwordMode"); |
| 275 | -addChoices(password_mode_choices, [this](char const* p) { c_main->passwordMode(p); }); | |
| 275 | +addChoices(password_mode_choices, true, [this](char const* p) { c_main->passwordMode(p); }); | |
| 276 | 276 | popHandler(); // key: passwordMode |
| 277 | 277 | pushKey("suppressPasswordRecovery"); |
| 278 | 278 | addBare([this]() { c_main->suppressPasswordRecovery(); }); |
| ... | ... | @@ -293,7 +293,7 @@ pushKey("iiMinBytes"); |
| 293 | 293 | addParameter([this](char const* p) { c_main->iiMinBytes(p); }); |
| 294 | 294 | popHandler(); // key: iiMinBytes |
| 295 | 295 | pushKey("removeUnreferencedResources"); |
| 296 | -addChoices(remove_unref_choices, [this](char const* p) { c_main->removeUnreferencedResources(p); }); | |
| 296 | +addChoices(remove_unref_choices, true, [this](char const* p) { c_main->removeUnreferencedResources(p); }); | |
| 297 | 297 | popHandler(); // key: removeUnreferencedResources |
| 298 | 298 | pushKey("addAttachment"); |
| 299 | 299 | beginArray(bindJSON(&Handlers::beginAddAttachmentArray), bindBare(&Handlers::endAddAttachmentArray)); // .addAttachment[] |
| ... | ... | @@ -345,7 +345,7 @@ pushKey("collate"); |
| 345 | 345 | addParameter([this](char const* p) { c_main->collate(p); }); |
| 346 | 346 | popHandler(); // key: collate |
| 347 | 347 | pushKey("flattenAnnotations"); |
| 348 | -addChoices(flatten_choices, [this](char const* p) { c_main->flattenAnnotations(p); }); | |
| 348 | +addChoices(flatten_choices, true, [this](char const* p) { c_main->flattenAnnotations(p); }); | |
| 349 | 349 | popHandler(); // key: flattenAnnotations |
| 350 | 350 | pushKey("flattenRotation"); |
| 351 | 351 | addBare([this]() { c_main->flattenRotation(); }); | ... | ... |
qpdf/qpdf.testcov
| ... | ... | @@ -630,7 +630,7 @@ qpdf check password password correct 0 |
| 630 | 630 | qpdf check password not encrypted 0 |
| 631 | 631 | QPDFJob_config password file 0 |
| 632 | 632 | QPDFJob_config password stdin 0 |
| 633 | -QPDFJob json bare not true 0 | |
| 633 | +QPDFJob json bare not empty 0 | |
| 634 | 634 | QPDFJob json choice mismatch 0 |
| 635 | 635 | QPDFJob json choice match 0 |
| 636 | 636 | QPDFJob json encrypt no key length 0 | ... | ... |
qpdf/qtest/qpdf/bad-bare-option-false-json.out
qpdf/qtest/qpdf/bad-json-bare-option-false.json
qpdf/qtest/qpdf/job-json-add-attachments.json
qpdf/qtest/qpdf/job-json-choice-match.json
qpdf/qtest/qpdf/job-json-copy-attachments.json
qpdf/qtest/qpdf/job-json-empty-input.json
qpdf/qtest/qpdf/job-json-encrypt-128.json
qpdf/qtest/qpdf/job-json-encrypt-256-with-restrictions.json
qpdf/qtest/qpdf/job-json-encrypt-40.json
qpdf/qtest/qpdf/job-json-input-file-password.json
qpdf/qtest/qpdf/job-json-misc-options.json
qpdf/qtest/qpdf/job-json-replace-input.json
qpdf/qtest/qpdf/job-json-underlay-overlay-password.json
qpdf/qtest/qpdf/job-json-underlay-overlay.json