aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2022-01-31 13:34:40 +0100
committerJay Berkenbilt <ejb@ql.org>2022-01-31 21:57:45 +0100
commit81b6314cb513f3e48c788722b9b024bf7c47a601 (patch)
tree82995960fac0f2f6da34a43850cb0037c9ed7c61 /libqpdf
parentf99e0af49c969529f36f287e23d4e178c40e8c4a (diff)
downloadqpdf-81b6314cb513f3e48c788722b9b024bf7c47a601.tar.zst
QPDFJob: fix logic errors in handling arrays
The code was assuming everything was happening inside dictionaries. Instead, make the dictionary key handler creatino explicit only when iterating through dictionary keys.
Diffstat (limited to 'libqpdf')
-rw-r--r--libqpdf/QPDFJob_json.cc170
-rw-r--r--libqpdf/qpdf/auto_job_json_decl.hh38
-rw-r--r--libqpdf/qpdf/auto_job_json_init.hh582
-rw-r--r--libqpdf/qpdf/auto_job_schema.hh4
4 files changed, 538 insertions, 256 deletions
diff --git a/libqpdf/QPDFJob_json.cc b/libqpdf/QPDFJob_json.cc
index 368b2a0a..967f0cc9 100644
--- a/libqpdf/QPDFJob_json.cc
+++ b/libqpdf/QPDFJob_json.cc
@@ -27,24 +27,20 @@ namespace
typedef std::function<void()> bare_handler_t;
typedef std::function<void(char const*)> param_handler_t;
typedef std::function<void(JSON)> json_handler_t;
- typedef std::function<void(std::string const& key)> setup_handler_t;
-
- void addBare(std::string const& key, bare_handler_t);
- void addParameter(std::string const& key, param_handler_t);
- void addChoices(std::string const& key, char const** choices,
- param_handler_t);
- void doSetup(std::string const& key, setup_handler_t);
- void beginDict(std::string const& key,
- json_handler_t start_fn,
+
+ void addBare(bare_handler_t);
+ void addParameter(param_handler_t);
+ void addChoices(char const** choices, param_handler_t);
+ void pushKey(std::string const& key);
+ void beginDict(json_handler_t start_fn,
bare_handler_t end_fn);
- void beginArray(std::string const& key,
- json_handler_t start_fn,
+ void beginArray(json_handler_t start_fn,
bare_handler_t end_fn);
- void endContainer();
+ void ignoreItem();
+ void popHandler();
bare_handler_t bindBare(void (Handlers::*f)());
json_handler_t bindJSON(void (Handlers::*f)(JSON));
- setup_handler_t bindSetup(void (Handlers::*f)(std::string const&));
std::list<std::shared_ptr<JSONHandler>> json_handlers;
bool partial;
@@ -84,12 +80,6 @@ Handlers::bindJSON(void (Handlers::*f)(JSON))
return std::bind(std::mem_fn(f), this, std::placeholders::_1);
}
-Handlers::setup_handler_t
-Handlers::bindSetup(void (Handlers::*f)(std::string const&))
-{
- return std::bind(std::mem_fn(f), this, std::placeholders::_1);
-}
-
void
Handlers::initHandlers()
{
@@ -113,10 +103,9 @@ Handlers::initHandlers()
}
void
-Handlers::addBare(std::string const& key, bare_handler_t fn)
+Handlers::addBare(bare_handler_t fn)
{
- auto h = std::make_shared<JSONHandler>();
- h->addBoolHandler([this, fn](std::string const& path, bool v){
+ jh->addBoolHandler([this, fn](std::string const& path, bool v){
if (! v)
{
usage(path + ": value must be true");
@@ -126,26 +115,22 @@ Handlers::addBare(std::string const& key, bare_handler_t fn)
fn();
}
});
- jh->addDictKeyHandler(key, h);
}
void
-Handlers::addParameter(std::string const& key, param_handler_t fn)
+Handlers::addParameter(param_handler_t fn)
{
- auto h = std::make_shared<JSONHandler>();
- h->addStringHandler(
+ jh->addStringHandler(
[fn](std::string const& path, std::string const& parameter){
fn(parameter.c_str());
});
- jh->addDictKeyHandler(key, h);
}
void
-Handlers::addChoices(std::string const& key, char const** choices,
+Handlers::addChoices(char const** choices,
param_handler_t fn)
{
- auto h = std::make_shared<JSONHandler>();
- h->addStringHandler(
+ jh->addStringHandler(
[fn, choices, this](
std::string const& path, std::string const& parameter){
@@ -180,47 +165,45 @@ Handlers::addChoices(std::string const& key, char const** choices,
}
fn(parameter.c_str());
});
- jh->addDictKeyHandler(key, h);
}
void
-Handlers::doSetup(std::string const& key, setup_handler_t fn)
+Handlers::pushKey(std::string const& key)
{
- fn(key);
+ auto new_jh = std::make_shared<JSONHandler>();
+ this->jh->addDictKeyHandler(key, new_jh);
+ this->json_handlers.push_back(new_jh);
+ this->jh = new_jh.get();
}
void
-Handlers::beginDict(std::string const& key,
- json_handler_t start_fn,
- bare_handler_t end_fn)
+Handlers::beginDict(json_handler_t start_fn, bare_handler_t end_fn)
{
- auto new_jh = std::make_shared<JSONHandler>();
- new_jh->addDictHandlers(
+ jh->addDictHandlers(
[start_fn](std::string const&, JSON j){ start_fn(j); },
[end_fn](std::string const&){ end_fn(); });
- this->jh->addDictKeyHandler(key, new_jh);
- this->json_handlers.push_back(new_jh);
- this->jh = new_jh.get();
}
void
-Handlers::beginArray(std::string const& key,
- json_handler_t start_fn,
- bare_handler_t end_fn)
+Handlers::beginArray(json_handler_t start_fn, bare_handler_t end_fn)
{
- auto new_jh = std::make_shared<JSONHandler>();
auto item_jh = std::make_shared<JSONHandler>();
- new_jh->addArrayHandlers(
+ jh->addArrayHandlers(
[start_fn](std::string const&, JSON j){ start_fn(j); },
[end_fn](std::string const&){ end_fn(); },
item_jh);
- this->jh->addDictKeyHandler(key, new_jh);
this->json_handlers.push_back(item_jh);
this->jh = item_jh.get();
}
void
-Handlers::endContainer()
+Handlers::ignoreItem()
+{
+ jh->addAnyHandler([](std::string const&, JSON){});
+}
+
+void
+Handlers::popHandler()
{
this->json_handlers.pop_back();
this->jh = this->json_handlers.back().get();
@@ -245,25 +228,25 @@ Handlers::endInput()
}
void
-Handlers::setupInputFilename(std::string const& key)
+Handlers::setupInputFilename()
{
- addParameter(key, [this](char const* p) {
+ addParameter([this](char const* p) {
c_main->inputFile(p);
});
}
void
-Handlers::setupInputPassword(std::string const& key)
+Handlers::setupInputPassword()
{
- addParameter(key, [this](char const* p) {
+ addParameter([this](char const* p) {
c_main->password(p);
});
}
void
-Handlers::setupInputEmpty(std::string const& key)
+Handlers::setupInputEmpty()
{
- addBare(key, [this]() {
+ addBare([this]() {
c_main->emptyInput();
});
}
@@ -281,17 +264,17 @@ Handlers::endOutput()
}
void
-Handlers::setupOutputFilename(std::string const& key)
+Handlers::setupOutputFilename()
{
- addParameter(key, [this](char const* p) {
+ addParameter([this](char const* p) {
c_main->outputFile(p);
});
}
void
-Handlers::setupOutputReplaceInput(std::string const& key)
+Handlers::setupOutputReplaceInput()
{
- addBare(key, [this]() {
+ addBare([this]() {
c_main->replaceInput();
});
}
@@ -359,15 +342,17 @@ Handlers::endOutputOptionsEncrypt()
}
void
-Handlers::setupOutputOptionsEncryptUserPassword(std::string const& key)
+Handlers::setupOutputOptionsEncryptUserPassword()
{
- // Key handled in beginOutputOptionsEncrypt
+ // handled in beginOutputOptionsEncrypt
+ ignoreItem();
}
void
-Handlers::setupOutputOptionsEncryptOwnerPassword(std::string const& key)
+Handlers::setupOutputOptionsEncryptOwnerPassword()
{
- // Key handled in beginOutputOptionsEncrypt
+ // handled in beginOutputOptionsEncrypt
+ ignoreItem();
}
void
@@ -431,6 +416,30 @@ Handlers::endInspect()
}
void
+Handlers::beginInspectJsonKeyArray(JSON)
+{
+ // nothing needed
+}
+
+void
+Handlers::endInspectJsonKeyArray()
+{
+ // nothing needed
+}
+
+void
+Handlers::beginInspectJsonObjectArray(JSON)
+{
+ // nothing needed
+}
+
+void
+Handlers::endInspectJsonObjectArray()
+{
+ // nothing needed
+}
+
+void
Handlers::beginOptionsAddAttachmentArray(JSON)
{
// nothing needed
@@ -456,9 +465,9 @@ Handlers::endOptionsAddAttachment()
}
void
-Handlers::setupOptionsAddAttachmentPath(std::string const& key)
+Handlers::setupOptionsAddAttachmentPath()
{
- addParameter(key, [this](char const* p) {
+ addParameter([this](char const* p) {
c_att->path(p);
});
}
@@ -489,17 +498,17 @@ Handlers::endOptionsCopyAttachmentsFrom()
}
void
-Handlers::setupOptionsCopyAttachmentsFromPath(std::string const& key)
+Handlers::setupOptionsCopyAttachmentsFromPath()
{
- addParameter(key, [this](char const* p) {
+ addParameter([this](char const* p) {
c_copy_att->path(p);
});
}
void
-Handlers::setupOptionsCopyAttachmentsFromPassword(std::string const& key)
+Handlers::setupOptionsCopyAttachmentsFromPassword()
{
- addParameter(key, [this](char const* p) {
+ addParameter([this](char const* p) {
c_copy_att->password(p);
});
}
@@ -554,21 +563,24 @@ Handlers::endOptionsPages()
}
void
-Handlers::setupOptionsPagesFile(std::string const& key)
+Handlers::setupOptionsPagesFile()
{
// handled in beginOptionsPages
+ ignoreItem();
}
void
-Handlers::setupOptionsPagesPassword(std::string const& key)
+Handlers::setupOptionsPagesPassword()
{
// handled in beginOptionsPages
+ ignoreItem();
}
void
-Handlers::setupOptionsPagesRange(std::string const& key)
+Handlers::setupOptionsPagesRange()
{
// handled in beginOptionsPages
+ ignoreItem();
}
void
@@ -585,17 +597,17 @@ Handlers::endOptionsOverlay()
}
void
-Handlers::setupOptionsOverlayFile(std::string const& key)
+Handlers::setupOptionsOverlayFile()
{
- addParameter(key, [this](char const* p) {
+ addParameter([this](char const* p) {
c_uo->path(p);
});
}
void
-Handlers::setupOptionsOverlayPassword(std::string const& key)
+Handlers::setupOptionsOverlayPassword()
{
- addParameter(key, [this](char const* p) {
+ addParameter([this](char const* p) {
c_uo->password(p);
});
}
@@ -614,17 +626,17 @@ Handlers::endOptionsUnderlay()
}
void
-Handlers::setupOptionsUnderlayFile(std::string const& key)
+Handlers::setupOptionsUnderlayFile()
{
- addParameter(key, [this](char const* p) {
+ addParameter([this](char const* p) {
c_uo->path(p);
});
}
void
-Handlers::setupOptionsUnderlayPassword(std::string const& key)
+Handlers::setupOptionsUnderlayPassword()
{
- addParameter(key, [this](char const* p) {
+ addParameter([this](char const* p) {
c_uo->password(p);
});
}
diff --git a/libqpdf/qpdf/auto_job_json_decl.hh b/libqpdf/qpdf/auto_job_json_decl.hh
index aa9b8137..8dc37adf 100644
--- a/libqpdf/qpdf/auto_job_json_decl.hh
+++ b/libqpdf/qpdf/auto_job_json_decl.hh
@@ -5,19 +5,19 @@
//
void beginInput(JSON);
void endInput();
-void setupInputFilename(std::string const&);
-void setupInputPassword(std::string const&);
-void setupInputEmpty(std::string const&);
+void setupInputFilename();
+void setupInputPassword();
+void setupInputEmpty();
void beginOutput(JSON);
void endOutput();
-void setupOutputFilename(std::string const&);
-void setupOutputReplaceInput(std::string const&);
+void setupOutputFilename();
+void setupOutputReplaceInput();
void beginOutputOptions(JSON);
void endOutputOptions();
void beginOutputOptionsEncrypt(JSON);
void endOutputOptionsEncrypt();
-void setupOutputOptionsEncryptUserPassword(std::string const&);
-void setupOutputOptionsEncryptOwnerPassword(std::string const&);
+void setupOutputOptionsEncryptUserPassword();
+void setupOutputOptionsEncryptOwnerPassword();
void beginOutputOptionsEncrypt40bit(JSON);
void endOutputOptionsEncrypt40bit();
void beginOutputOptionsEncrypt128bit(JSON);
@@ -26,31 +26,35 @@ void beginOutputOptionsEncrypt256bit(JSON);
void endOutputOptionsEncrypt256bit();
void beginInspect(JSON);
void endInspect();
+void beginInspectJsonKeyArray(JSON);
+void endInspectJsonKeyArray();
+void beginInspectJsonObjectArray(JSON);
+void endInspectJsonObjectArray();
void beginOptions(JSON);
void endOptions();
void beginOptionsAddAttachmentArray(JSON);
void endOptionsAddAttachmentArray();
void beginOptionsAddAttachment(JSON);
void endOptionsAddAttachment();
-void setupOptionsAddAttachmentPath(std::string const&);
+void setupOptionsAddAttachmentPath();
void beginOptionsCopyAttachmentsFromArray(JSON);
void endOptionsCopyAttachmentsFromArray();
void beginOptionsCopyAttachmentsFrom(JSON);
void endOptionsCopyAttachmentsFrom();
-void setupOptionsCopyAttachmentsFromPath(std::string const&);
-void setupOptionsCopyAttachmentsFromPassword(std::string const&);
+void setupOptionsCopyAttachmentsFromPath();
+void setupOptionsCopyAttachmentsFromPassword();
void beginOptionsPagesArray(JSON);
void endOptionsPagesArray();
void beginOptionsPages(JSON);
void endOptionsPages();
-void setupOptionsPagesFile(std::string const&);
-void setupOptionsPagesPassword(std::string const&);
-void setupOptionsPagesRange(std::string const&);
+void setupOptionsPagesFile();
+void setupOptionsPagesPassword();
+void setupOptionsPagesRange();
void beginOptionsOverlay(JSON);
void endOptionsOverlay();
-void setupOptionsOverlayFile(std::string const&);
-void setupOptionsOverlayPassword(std::string const&);
+void setupOptionsOverlayFile();
+void setupOptionsOverlayPassword();
void beginOptionsUnderlay(JSON);
void endOptionsUnderlay();
-void setupOptionsUnderlayFile(std::string const&);
-void setupOptionsUnderlayPassword(std::string const&);
+void setupOptionsUnderlayFile();
+void setupOptionsUnderlayPassword();
diff --git a/libqpdf/qpdf/auto_job_json_init.hh b/libqpdf/qpdf/auto_job_json_init.hh
index 87489412..3e082b84 100644
--- a/libqpdf/qpdf/auto_job_json_init.hh
+++ b/libqpdf/qpdf/auto_job_json_init.hh
@@ -14,161 +14,427 @@ static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "
static char const* print128_choices[] = {"full", "low", "none", 0};
static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0};
-beginDict("input", bindJSON(&Handlers::beginInput), bindBare(&Handlers::endInput)); // .input
-doSetup("filename", bindSetup(&Handlers::setupInputFilename));
-doSetup("password", bindSetup(&Handlers::setupInputPassword));
-addParameter("passwordFile", [this](char const* p) { c_main->passwordFile(p); });
-doSetup("empty", bindSetup(&Handlers::setupInputEmpty));
-endContainer(); // .input
-beginDict("output", bindJSON(&Handlers::beginOutput), bindBare(&Handlers::endOutput)); // .output
-doSetup("filename", bindSetup(&Handlers::setupOutputFilename));
-doSetup("replaceInput", bindSetup(&Handlers::setupOutputReplaceInput));
-beginDict("options", bindJSON(&Handlers::beginOutputOptions), bindBare(&Handlers::endOutputOptions)); // .output.options
-addBare("qdf", [this]() { c_main->qdf(); });
-addBare("preserveUnreferenced", [this]() { c_main->preserveUnreferenced(); });
-addBare("newlineBeforeEndstream", [this]() { c_main->newlineBeforeEndstream(); });
-addChoices("normalizeContent", yn_choices, [this](char const* p) { c_main->normalizeContent(p); });
-addChoices("streamData", stream_data_choices, [this](char const* p) { c_main->streamData(p); });
-addChoices("compressStreams", yn_choices, [this](char const* p) { c_main->compressStreams(p); });
-addBare("recompressFlate", [this]() { c_main->recompressFlate(); });
-addChoices("decodeLevel", decode_level_choices, [this](char const* p) { c_main->decodeLevel(p); });
-addBare("decrypt", [this]() { c_main->decrypt(); });
-addBare("staticAesIv", [this]() { c_main->staticAesIv(); });
-addBare("staticId", [this]() { c_main->staticId(); });
-addBare("noOriginalObjectIds", [this]() { c_main->noOriginalObjectIds(); });
-addParameter("copyEncryption", [this](char const* p) { c_main->copyEncryption(p); });
-addParameter("encryptionFilePassword", [this](char const* p) { c_main->encryptionFilePassword(p); });
-addBare("linearize", [this]() { c_main->linearize(); });
-addParameter("linearizePass1", [this](char const* p) { c_main->linearizePass1(p); });
-addChoices("objectStreams", object_streams_choices, [this](char const* p) { c_main->objectStreams(p); });
-addParameter("minVersion", [this](char const* p) { c_main->minVersion(p); });
-addParameter("forceVersion", [this](char const* p) { c_main->forceVersion(p); });
-addBare("progress", [this]() { c_main->progress(); });
-addParameter("splitPages", [this](char const* p) { c_main->splitPages(p); });
-beginDict("encrypt", bindJSON(&Handlers::beginOutputOptionsEncrypt), bindBare(&Handlers::endOutputOptionsEncrypt)); // .output.options.encrypt
-doSetup("userPassword", bindSetup(&Handlers::setupOutputOptionsEncryptUserPassword));
-doSetup("ownerPassword", bindSetup(&Handlers::setupOutputOptionsEncryptOwnerPassword));
-beginDict("40bit", bindJSON(&Handlers::beginOutputOptionsEncrypt40bit), bindBare(&Handlers::endOutputOptionsEncrypt40bit)); // .output.options.encrypt.40bit
-addChoices("annotate", yn_choices, [this](char const* p) { c_enc->annotate(p); });
-addChoices("extract", yn_choices, [this](char const* p) { c_enc->extract(p); });
-addChoices("modify", modify128_choices, [this](char const* p) { c_enc->modify(p); });
-addChoices("print", print128_choices, [this](char const* p) { c_enc->print(p); });
-endContainer(); // .output.options.encrypt.40bit
-beginDict("128bit", bindJSON(&Handlers::beginOutputOptionsEncrypt128bit), bindBare(&Handlers::endOutputOptionsEncrypt128bit)); // .output.options.encrypt.128bit
-addChoices("accessibility", yn_choices, [this](char const* p) { c_enc->accessibility(p); });
-addChoices("annotate", yn_choices, [this](char const* p) { c_enc->annotate(p); });
-addChoices("assemble", yn_choices, [this](char const* p) { c_enc->assemble(p); });
-addBare("cleartextMetadata", [this]() { c_enc->cleartextMetadata(); });
-addChoices("extract", yn_choices, [this](char const* p) { c_enc->extract(p); });
-addChoices("form", yn_choices, [this](char const* p) { c_enc->form(p); });
-addChoices("modifyOther", yn_choices, [this](char const* p) { c_enc->modifyOther(p); });
-addChoices("modify", modify128_choices, [this](char const* p) { c_enc->modify(p); });
-addChoices("print", print128_choices, [this](char const* p) { c_enc->print(p); });
-addBare("forceV4", [this]() { c_enc->forceV4(); });
-addChoices("useAes", yn_choices, [this](char const* p) { c_enc->useAes(p); });
-endContainer(); // .output.options.encrypt.128bit
-beginDict("256bit", bindJSON(&Handlers::beginOutputOptionsEncrypt256bit), bindBare(&Handlers::endOutputOptionsEncrypt256bit)); // .output.options.encrypt.256bit
-addChoices("accessibility", yn_choices, [this](char const* p) { c_enc->accessibility(p); });
-addChoices("annotate", yn_choices, [this](char const* p) { c_enc->annotate(p); });
-addChoices("assemble", yn_choices, [this](char const* p) { c_enc->assemble(p); });
-addBare("cleartextMetadata", [this]() { c_enc->cleartextMetadata(); });
-addChoices("extract", yn_choices, [this](char const* p) { c_enc->extract(p); });
-addChoices("form", yn_choices, [this](char const* p) { c_enc->form(p); });
-addChoices("modifyOther", yn_choices, [this](char const* p) { c_enc->modifyOther(p); });
-addChoices("modify", modify128_choices, [this](char const* p) { c_enc->modify(p); });
-addChoices("print", print128_choices, [this](char const* p) { c_enc->print(p); });
-addBare("allowInsecure", [this]() { c_enc->allowInsecure(); });
-addBare("forceR5", [this]() { c_enc->forceR5(); });
-endContainer(); // .output.options.encrypt.256bit
-endContainer(); // .output.options.encrypt
-endContainer(); // .output.options
-endContainer(); // .output
-beginDict("inspect", bindJSON(&Handlers::beginInspect), bindBare(&Handlers::endInspect)); // .inspect
-addBare("check", [this]() { c_main->check(); });
-addBare("checkLinearization", [this]() { c_main->checkLinearization(); });
-addBare("filteredStreamData", [this]() { c_main->filteredStreamData(); });
-addBare("rawStreamData", [this]() { c_main->rawStreamData(); });
-addBare("showEncryption", [this]() { c_main->showEncryption(); });
-addBare("showEncryptionKey", [this]() { c_main->showEncryptionKey(); });
-addBare("showLinearization", [this]() { c_main->showLinearization(); });
-addBare("showNpages", [this]() { c_main->showNpages(); });
-addParameter("showObject", [this](char const* p) { c_main->showObject(p); });
-addBare("showPages", [this]() { c_main->showPages(); });
-addBare("showXref", [this]() { c_main->showXref(); });
-addBare("withImages", [this]() { c_main->withImages(); });
-addBare("listAttachments", [this]() { c_main->listAttachments(); });
-addParameter("showAttachment", [this](char const* p) { c_main->showAttachment(p); });
-addBare("json", [this]() { c_main->json(); });
-addChoices("jsonKey", json_key_choices, [this](char const* p) { c_main->jsonKey(p); });
-addParameter("jsonObject", [this](char const* p) { c_main->jsonObject(p); });
-endContainer(); // .inspect
-beginDict("options", bindJSON(&Handlers::beginOptions), bindBare(&Handlers::endOptions)); // .options
-addBare("allowWeakCrypto", [this]() { c_main->allowWeakCrypto(); });
-addBare("deterministicId", [this]() { c_main->deterministicId(); });
-addChoices("keepFilesOpen", yn_choices, [this](char const* p) { c_main->keepFilesOpen(p); });
-addParameter("keepFilesOpenThreshold", [this](char const* p) { c_main->keepFilesOpenThreshold(p); });
-addBare("noWarn", [this]() { c_main->noWarn(); });
-addBare("verbose", [this]() { c_main->verbose(); });
-addBare("ignoreXrefStreams", [this]() { c_main->ignoreXrefStreams(); });
-addBare("passwordIsHexKey", [this]() { c_main->passwordIsHexKey(); });
-addChoices("passwordMode", password_mode_choices, [this](char const* p) { c_main->passwordMode(p); });
-addBare("suppressPasswordRecovery", [this]() { c_main->suppressPasswordRecovery(); });
-addBare("suppressRecovery", [this]() { c_main->suppressRecovery(); });
-addBare("coalesceContents", [this]() { c_main->coalesceContents(); });
-addParameter("compressionLevel", [this](char const* p) { c_main->compressionLevel(p); });
-addBare("externalizeInlineImages", [this]() { c_main->externalizeInlineImages(); });
-addParameter("iiMinBytes", [this](char const* p) { c_main->iiMinBytes(p); });
-addChoices("removeUnreferencedResources", remove_unref_choices, [this](char const* p) { c_main->removeUnreferencedResources(p); });
-beginArray("options", bindJSON(&Handlers::beginOptionsAddAttachmentArray), bindBare(&Handlers::endOptionsAddAttachmentArray)); // .options.addAttachment[]
-beginDict("addAttachment", bindJSON(&Handlers::beginOptionsAddAttachment), bindBare(&Handlers::endOptionsAddAttachment)); // .options.addAttachment
-doSetup("path", bindSetup(&Handlers::setupOptionsAddAttachmentPath));
-addParameter("creationdate", [this](char const* p) { c_att->creationdate(p); });
-addParameter("description", [this](char const* p) { c_att->description(p); });
-addParameter("filename", [this](char const* p) { c_att->filename(p); });
-addParameter("key", [this](char const* p) { c_att->key(p); });
-addParameter("mimetype", [this](char const* p) { c_att->mimetype(p); });
-addParameter("moddate", [this](char const* p) { c_att->moddate(p); });
-addBare("replace", [this]() { c_att->replace(); });
-endContainer(); // .options.addAttachment
-endContainer(); // .options.addAttachment[]
-addParameter("removeAttachment", [this](char const* p) { c_main->removeAttachment(p); });
-beginArray("options", bindJSON(&Handlers::beginOptionsCopyAttachmentsFromArray), bindBare(&Handlers::endOptionsCopyAttachmentsFromArray)); // .options.copyAttachmentsFrom[]
-beginDict("copyAttachmentsFrom", bindJSON(&Handlers::beginOptionsCopyAttachmentsFrom), bindBare(&Handlers::endOptionsCopyAttachmentsFrom)); // .options.copyAttachmentsFrom
-doSetup("path", bindSetup(&Handlers::setupOptionsCopyAttachmentsFromPath));
-doSetup("password", bindSetup(&Handlers::setupOptionsCopyAttachmentsFromPassword));
-addParameter("prefix", [this](char const* p) { c_copy_att->prefix(p); });
-endContainer(); // .options.copyAttachmentsFrom
-endContainer(); // .options.copyAttachmentsFrom[]
-addParameter("collate", [this](char const* p) { c_main->collate(p); });
-addChoices("flattenAnnotations", flatten_choices, [this](char const* p) { c_main->flattenAnnotations(p); });
-addBare("flattenRotation", [this]() { c_main->flattenRotation(); });
-addBare("generateAppearances", [this]() { c_main->generateAppearances(); });
-addBare("keepInlineImages", [this]() { c_main->keepInlineImages(); });
-addParameter("oiMinArea", [this](char const* p) { c_main->oiMinArea(p); });
-addParameter("oiMinHeight", [this](char const* p) { c_main->oiMinHeight(p); });
-addParameter("oiMinWidth", [this](char const* p) { c_main->oiMinWidth(p); });
-addBare("optimizeImages", [this]() { c_main->optimizeImages(); });
-beginArray("options", bindJSON(&Handlers::beginOptionsPagesArray), bindBare(&Handlers::endOptionsPagesArray)); // .options.pages[]
-beginDict("pages", bindJSON(&Handlers::beginOptionsPages), bindBare(&Handlers::endOptionsPages)); // .options.pages
-doSetup("file", bindSetup(&Handlers::setupOptionsPagesFile));
-doSetup("password", bindSetup(&Handlers::setupOptionsPagesPassword));
-doSetup("range", bindSetup(&Handlers::setupOptionsPagesRange));
-endContainer(); // .options.pages
-endContainer(); // .options.pages[]
-addBare("removePageLabels", [this]() { c_main->removePageLabels(); });
-addParameter("rotate", [this](char const* p) { c_main->rotate(p); });
-beginDict("overlay", bindJSON(&Handlers::beginOptionsOverlay), bindBare(&Handlers::endOptionsOverlay)); // .options.overlay
-doSetup("file", bindSetup(&Handlers::setupOptionsOverlayFile));
-doSetup("password", bindSetup(&Handlers::setupOptionsOverlayPassword));
-addParameter("from", [this](char const* p) { c_uo->from(p); });
-addParameter("repeat", [this](char const* p) { c_uo->repeat(p); });
-addParameter("to", [this](char const* p) { c_uo->to(p); });
-endContainer(); // .options.overlay
-beginDict("underlay", bindJSON(&Handlers::beginOptionsUnderlay), bindBare(&Handlers::endOptionsUnderlay)); // .options.underlay
-doSetup("file", bindSetup(&Handlers::setupOptionsUnderlayFile));
-doSetup("password", bindSetup(&Handlers::setupOptionsUnderlayPassword));
-addParameter("from", [this](char const* p) { c_uo->from(p); });
-addParameter("repeat", [this](char const* p) { c_uo->repeat(p); });
-addParameter("to", [this](char const* p) { c_uo->to(p); });
-endContainer(); // .options.underlay
-endContainer(); // .options
+pushKey("input");
+beginDict(bindJSON(&Handlers::beginInput), bindBare(&Handlers::endInput)); // .input
+pushKey("filename");
+setupInputFilename();
+popHandler(); // key: filename
+pushKey("password");
+setupInputPassword();
+popHandler(); // key: password
+pushKey("passwordFile");
+addParameter([this](char const* p) { c_main->passwordFile(p); });
+popHandler(); // key: passwordFile
+pushKey("empty");
+setupInputEmpty();
+popHandler(); // key: empty
+popHandler(); // key: input
+pushKey("output");
+beginDict(bindJSON(&Handlers::beginOutput), bindBare(&Handlers::endOutput)); // .output
+pushKey("filename");
+setupOutputFilename();
+popHandler(); // key: filename
+pushKey("replaceInput");
+setupOutputReplaceInput();
+popHandler(); // key: replaceInput
+pushKey("options");
+beginDict(bindJSON(&Handlers::beginOutputOptions), bindBare(&Handlers::endOutputOptions)); // .output.options
+pushKey("qdf");
+addBare([this]() { c_main->qdf(); });
+popHandler(); // key: qdf
+pushKey("preserveUnreferenced");
+addBare([this]() { c_main->preserveUnreferenced(); });
+popHandler(); // key: preserveUnreferenced
+pushKey("newlineBeforeEndstream");
+addBare([this]() { c_main->newlineBeforeEndstream(); });
+popHandler(); // key: newlineBeforeEndstream
+pushKey("normalizeContent");
+addChoices(yn_choices, [this](char const* p) { c_main->normalizeContent(p); });
+popHandler(); // key: normalizeContent
+pushKey("streamData");
+addChoices(stream_data_choices, [this](char const* p) { c_main->streamData(p); });
+popHandler(); // key: streamData
+pushKey("compressStreams");
+addChoices(yn_choices, [this](char const* p) { c_main->compressStreams(p); });
+popHandler(); // key: compressStreams
+pushKey("recompressFlate");
+addBare([this]() { c_main->recompressFlate(); });
+popHandler(); // key: recompressFlate
+pushKey("decodeLevel");
+addChoices(decode_level_choices, [this](char const* p) { c_main->decodeLevel(p); });
+popHandler(); // key: decodeLevel
+pushKey("decrypt");
+addBare([this]() { c_main->decrypt(); });
+popHandler(); // key: decrypt
+pushKey("staticAesIv");
+addBare([this]() { c_main->staticAesIv(); });
+popHandler(); // key: staticAesIv
+pushKey("staticId");
+addBare([this]() { c_main->staticId(); });
+popHandler(); // key: staticId
+pushKey("noOriginalObjectIds");
+addBare([this]() { c_main->noOriginalObjectIds(); });
+popHandler(); // key: noOriginalObjectIds
+pushKey("copyEncryption");
+addParameter([this](char const* p) { c_main->copyEncryption(p); });
+popHandler(); // key: copyEncryption
+pushKey("encryptionFilePassword");
+addParameter([this](char const* p) { c_main->encryptionFilePassword(p); });
+popHandler(); // key: encryptionFilePassword
+pushKey("linearize");
+addBare([this]() { c_main->linearize(); });
+popHandler(); // key: linearize
+pushKey("linearizePass1");
+addParameter([this](char const* p) { c_main->linearizePass1(p); });
+popHandler(); // key: linearizePass1
+pushKey("objectStreams");
+addChoices(object_streams_choices, [this](char const* p) { c_main->objectStreams(p); });
+popHandler(); // key: objectStreams
+pushKey("minVersion");
+addParameter([this](char const* p) { c_main->minVersion(p); });
+popHandler(); // key: minVersion
+pushKey("forceVersion");
+addParameter([this](char const* p) { c_main->forceVersion(p); });
+popHandler(); // key: forceVersion
+pushKey("progress");
+addBare([this]() { c_main->progress(); });
+popHandler(); // key: progress
+pushKey("splitPages");
+addParameter([this](char const* p) { c_main->splitPages(p); });
+popHandler(); // key: splitPages
+pushKey("encrypt");
+beginDict(bindJSON(&Handlers::beginOutputOptionsEncrypt), bindBare(&Handlers::endOutputOptionsEncrypt)); // .output.options.encrypt
+pushKey("userPassword");
+setupOutputOptionsEncryptUserPassword();
+popHandler(); // key: userPassword
+pushKey("ownerPassword");
+setupOutputOptionsEncryptOwnerPassword();
+popHandler(); // key: ownerPassword
+pushKey("40bit");
+beginDict(bindJSON(&Handlers::beginOutputOptionsEncrypt40bit), bindBare(&Handlers::endOutputOptionsEncrypt40bit)); // .output.options.encrypt.40bit
+pushKey("annotate");
+addChoices(yn_choices, [this](char const* p) { c_enc->annotate(p); });
+popHandler(); // key: annotate
+pushKey("extract");
+addChoices(yn_choices, [this](char const* p) { c_enc->extract(p); });
+popHandler(); // key: extract
+pushKey("modify");
+addChoices(modify128_choices, [this](char const* p) { c_enc->modify(p); });
+popHandler(); // key: modify
+pushKey("print");
+addChoices(print128_choices, [this](char const* p) { c_enc->print(p); });
+popHandler(); // key: print
+popHandler(); // key: 40bit
+pushKey("128bit");
+beginDict(bindJSON(&Handlers::beginOutputOptionsEncrypt128bit), bindBare(&Handlers::endOutputOptionsEncrypt128bit)); // .output.options.encrypt.128bit
+pushKey("accessibility");
+addChoices(yn_choices, [this](char const* p) { c_enc->accessibility(p); });
+popHandler(); // key: accessibility
+pushKey("annotate");
+addChoices(yn_choices, [this](char const* p) { c_enc->annotate(p); });
+popHandler(); // key: annotate
+pushKey("assemble");
+addChoices(yn_choices, [this](char const* p) { c_enc->assemble(p); });
+popHandler(); // key: assemble
+pushKey("cleartextMetadata");
+addBare([this]() { c_enc->cleartextMetadata(); });
+popHandler(); // key: cleartextMetadata
+pushKey("extract");
+addChoices(yn_choices, [this](char const* p) { c_enc->extract(p); });
+popHandler(); // key: extract
+pushKey("form");
+addChoices(yn_choices, [this](char const* p) { c_enc->form(p); });
+popHandler(); // key: form
+pushKey("modifyOther");
+addChoices(yn_choices, [this](char const* p) { c_enc->modifyOther(p); });
+popHandler(); // key: modifyOther
+pushKey("modify");
+addChoices(modify128_choices, [this](char const* p) { c_enc->modify(p); });
+popHandler(); // key: modify
+pushKey("print");
+addChoices(print128_choices, [this](char const* p) { c_enc->print(p); });
+popHandler(); // key: print
+pushKey("forceV4");
+addBare([this]() { c_enc->forceV4(); });
+popHandler(); // key: forceV4
+pushKey("useAes");
+addChoices(yn_choices, [this](char const* p) { c_enc->useAes(p); });
+popHandler(); // key: useAes
+popHandler(); // key: 128bit
+pushKey("256bit");
+beginDict(bindJSON(&Handlers::beginOutputOptionsEncrypt256bit), bindBare(&Handlers::endOutputOptionsEncrypt256bit)); // .output.options.encrypt.256bit
+pushKey("accessibility");
+addChoices(yn_choices, [this](char const* p) { c_enc->accessibility(p); });
+popHandler(); // key: accessibility
+pushKey("annotate");
+addChoices(yn_choices, [this](char const* p) { c_enc->annotate(p); });
+popHandler(); // key: annotate
+pushKey("assemble");
+addChoices(yn_choices, [this](char const* p) { c_enc->assemble(p); });
+popHandler(); // key: assemble
+pushKey("cleartextMetadata");
+addBare([this]() { c_enc->cleartextMetadata(); });
+popHandler(); // key: cleartextMetadata
+pushKey("extract");
+addChoices(yn_choices, [this](char const* p) { c_enc->extract(p); });
+popHandler(); // key: extract
+pushKey("form");
+addChoices(yn_choices, [this](char const* p) { c_enc->form(p); });
+popHandler(); // key: form
+pushKey("modifyOther");
+addChoices(yn_choices, [this](char const* p) { c_enc->modifyOther(p); });
+popHandler(); // key: modifyOther
+pushKey("modify");
+addChoices(modify128_choices, [this](char const* p) { c_enc->modify(p); });
+popHandler(); // key: modify
+pushKey("print");
+addChoices(print128_choices, [this](char const* p) { c_enc->print(p); });
+popHandler(); // key: print
+pushKey("allowInsecure");
+addBare([this]() { c_enc->allowInsecure(); });
+popHandler(); // key: allowInsecure
+pushKey("forceR5");
+addBare([this]() { c_enc->forceR5(); });
+popHandler(); // key: forceR5
+popHandler(); // key: 256bit
+popHandler(); // key: encrypt
+popHandler(); // key: options
+popHandler(); // key: output
+pushKey("inspect");
+beginDict(bindJSON(&Handlers::beginInspect), bindBare(&Handlers::endInspect)); // .inspect
+pushKey("check");
+addBare([this]() { c_main->check(); });
+popHandler(); // key: check
+pushKey("checkLinearization");
+addBare([this]() { c_main->checkLinearization(); });
+popHandler(); // key: checkLinearization
+pushKey("filteredStreamData");
+addBare([this]() { c_main->filteredStreamData(); });
+popHandler(); // key: filteredStreamData
+pushKey("rawStreamData");
+addBare([this]() { c_main->rawStreamData(); });
+popHandler(); // key: rawStreamData
+pushKey("showEncryption");
+addBare([this]() { c_main->showEncryption(); });
+popHandler(); // key: showEncryption
+pushKey("showEncryptionKey");
+addBare([this]() { c_main->showEncryptionKey(); });
+popHandler(); // key: showEncryptionKey
+pushKey("showLinearization");
+addBare([this]() { c_main->showLinearization(); });
+popHandler(); // key: showLinearization
+pushKey("showNpages");
+addBare([this]() { c_main->showNpages(); });
+popHandler(); // key: showNpages
+pushKey("showObject");
+addParameter([this](char const* p) { c_main->showObject(p); });
+popHandler(); // key: showObject
+pushKey("showPages");
+addBare([this]() { c_main->showPages(); });
+popHandler(); // key: showPages
+pushKey("showXref");
+addBare([this]() { c_main->showXref(); });
+popHandler(); // key: showXref
+pushKey("withImages");
+addBare([this]() { c_main->withImages(); });
+popHandler(); // key: withImages
+pushKey("listAttachments");
+addBare([this]() { c_main->listAttachments(); });
+popHandler(); // key: listAttachments
+pushKey("showAttachment");
+addParameter([this](char const* p) { c_main->showAttachment(p); });
+popHandler(); // key: showAttachment
+pushKey("json");
+addBare([this]() { c_main->json(); });
+popHandler(); // key: json
+pushKey("jsonKey");
+beginArray(bindJSON(&Handlers::beginInspectJsonKeyArray), bindBare(&Handlers::endInspectJsonKeyArray)); // .inspect.jsonKey[]
+addChoices(json_key_choices, [this](char const* p) { c_main->jsonKey(p); });
+popHandler(); // array: .inspect.jsonKey[]
+popHandler(); // key: jsonKey
+pushKey("jsonObject");
+beginArray(bindJSON(&Handlers::beginInspectJsonObjectArray), bindBare(&Handlers::endInspectJsonObjectArray)); // .inspect.jsonObject[]
+addParameter([this](char const* p) { c_main->jsonObject(p); });
+popHandler(); // array: .inspect.jsonObject[]
+popHandler(); // key: jsonObject
+popHandler(); // key: inspect
+pushKey("options");
+beginDict(bindJSON(&Handlers::beginOptions), bindBare(&Handlers::endOptions)); // .options
+pushKey("allowWeakCrypto");
+addBare([this]() { c_main->allowWeakCrypto(); });
+popHandler(); // key: allowWeakCrypto
+pushKey("deterministicId");
+addBare([this]() { c_main->deterministicId(); });
+popHandler(); // key: deterministicId
+pushKey("keepFilesOpen");
+addChoices(yn_choices, [this](char const* p) { c_main->keepFilesOpen(p); });
+popHandler(); // key: keepFilesOpen
+pushKey("keepFilesOpenThreshold");
+addParameter([this](char const* p) { c_main->keepFilesOpenThreshold(p); });
+popHandler(); // key: keepFilesOpenThreshold
+pushKey("noWarn");
+addBare([this]() { c_main->noWarn(); });
+popHandler(); // key: noWarn
+pushKey("verbose");
+addBare([this]() { c_main->verbose(); });
+popHandler(); // key: verbose
+pushKey("ignoreXrefStreams");
+addBare([this]() { c_main->ignoreXrefStreams(); });
+popHandler(); // key: ignoreXrefStreams
+pushKey("passwordIsHexKey");
+addBare([this]() { c_main->passwordIsHexKey(); });
+popHandler(); // key: passwordIsHexKey
+pushKey("passwordMode");
+addChoices(password_mode_choices, [this](char const* p) { c_main->passwordMode(p); });
+popHandler(); // key: passwordMode
+pushKey("suppressPasswordRecovery");
+addBare([this]() { c_main->suppressPasswordRecovery(); });
+popHandler(); // key: suppressPasswordRecovery
+pushKey("suppressRecovery");
+addBare([this]() { c_main->suppressRecovery(); });
+popHandler(); // key: suppressRecovery
+pushKey("coalesceContents");
+addBare([this]() { c_main->coalesceContents(); });
+popHandler(); // key: coalesceContents
+pushKey("compressionLevel");
+addParameter([this](char const* p) { c_main->compressionLevel(p); });
+popHandler(); // key: compressionLevel
+pushKey("externalizeInlineImages");
+addBare([this]() { c_main->externalizeInlineImages(); });
+popHandler(); // key: externalizeInlineImages
+pushKey("iiMinBytes");
+addParameter([this](char const* p) { c_main->iiMinBytes(p); });
+popHandler(); // key: iiMinBytes
+pushKey("removeUnreferencedResources");
+addChoices(remove_unref_choices, [this](char const* p) { c_main->removeUnreferencedResources(p); });
+popHandler(); // key: removeUnreferencedResources
+pushKey("addAttachment");
+beginArray(bindJSON(&Handlers::beginOptionsAddAttachmentArray), bindBare(&Handlers::endOptionsAddAttachmentArray)); // .options.addAttachment[]
+beginDict(bindJSON(&Handlers::beginOptionsAddAttachment), bindBare(&Handlers::endOptionsAddAttachment)); // .options.addAttachment
+pushKey("path");
+setupOptionsAddAttachmentPath();
+popHandler(); // key: path
+pushKey("creationdate");
+addParameter([this](char const* p) { c_att->creationdate(p); });
+popHandler(); // key: creationdate
+pushKey("description");
+addParameter([this](char const* p) { c_att->description(p); });
+popHandler(); // key: description
+pushKey("filename");
+addParameter([this](char const* p) { c_att->filename(p); });
+popHandler(); // key: filename
+pushKey("key");
+addParameter([this](char const* p) { c_att->key(p); });
+popHandler(); // key: key
+pushKey("mimetype");
+addParameter([this](char const* p) { c_att->mimetype(p); });
+popHandler(); // key: mimetype
+pushKey("moddate");
+addParameter([this](char const* p) { c_att->moddate(p); });
+popHandler(); // key: moddate
+pushKey("replace");
+addBare([this]() { c_att->replace(); });
+popHandler(); // key: replace
+popHandler(); // array: .options.addAttachment[]
+popHandler(); // key: addAttachment
+pushKey("removeAttachment");
+addParameter([this](char const* p) { c_main->removeAttachment(p); });
+popHandler(); // key: removeAttachment
+pushKey("copyAttachmentsFrom");
+beginArray(bindJSON(&Handlers::beginOptionsCopyAttachmentsFromArray), bindBare(&Handlers::endOptionsCopyAttachmentsFromArray)); // .options.copyAttachmentsFrom[]
+beginDict(bindJSON(&Handlers::beginOptionsCopyAttachmentsFrom), bindBare(&Handlers::endOptionsCopyAttachmentsFrom)); // .options.copyAttachmentsFrom
+pushKey("path");
+setupOptionsCopyAttachmentsFromPath();
+popHandler(); // key: path
+pushKey("password");
+setupOptionsCopyAttachmentsFromPassword();
+popHandler(); // key: password
+pushKey("prefix");
+addParameter([this](char const* p) { c_copy_att->prefix(p); });
+popHandler(); // key: prefix
+popHandler(); // array: .options.copyAttachmentsFrom[]
+popHandler(); // key: copyAttachmentsFrom
+pushKey("collate");
+addParameter([this](char const* p) { c_main->collate(p); });
+popHandler(); // key: collate
+pushKey("flattenAnnotations");
+addChoices(flatten_choices, [this](char const* p) { c_main->flattenAnnotations(p); });
+popHandler(); // key: flattenAnnotations
+pushKey("flattenRotation");
+addBare([this]() { c_main->flattenRotation(); });
+popHandler(); // key: flattenRotation
+pushKey("generateAppearances");
+addBare([this]() { c_main->generateAppearances(); });
+popHandler(); // key: generateAppearances
+pushKey("keepInlineImages");
+addBare([this]() { c_main->keepInlineImages(); });
+popHandler(); // key: keepInlineImages
+pushKey("oiMinArea");
+addParameter([this](char const* p) { c_main->oiMinArea(p); });
+popHandler(); // key: oiMinArea
+pushKey("oiMinHeight");
+addParameter([this](char const* p) { c_main->oiMinHeight(p); });
+popHandler(); // key: oiMinHeight
+pushKey("oiMinWidth");
+addParameter([this](char const* p) { c_main->oiMinWidth(p); });
+popHandler(); // key: oiMinWidth
+pushKey("optimizeImages");
+addBare([this]() { c_main->optimizeImages(); });
+popHandler(); // key: optimizeImages
+pushKey("pages");
+beginArray(bindJSON(&Handlers::beginOptionsPagesArray), bindBare(&Handlers::endOptionsPagesArray)); // .options.pages[]
+beginDict(bindJSON(&Handlers::beginOptionsPages), bindBare(&Handlers::endOptionsPages)); // .options.pages
+pushKey("file");
+setupOptionsPagesFile();
+popHandler(); // key: file
+pushKey("password");
+setupOptionsPagesPassword();
+popHandler(); // key: password
+pushKey("range");
+setupOptionsPagesRange();
+popHandler(); // key: range
+popHandler(); // array: .options.pages[]
+popHandler(); // key: pages
+pushKey("removePageLabels");
+addBare([this]() { c_main->removePageLabels(); });
+popHandler(); // key: removePageLabels
+pushKey("rotate");
+addParameter([this](char const* p) { c_main->rotate(p); });
+popHandler(); // key: rotate
+pushKey("overlay");
+beginDict(bindJSON(&Handlers::beginOptionsOverlay), bindBare(&Handlers::endOptionsOverlay)); // .options.overlay
+pushKey("file");
+setupOptionsOverlayFile();
+popHandler(); // key: file
+pushKey("password");
+setupOptionsOverlayPassword();
+popHandler(); // key: password
+pushKey("from");
+addParameter([this](char const* p) { c_uo->from(p); });
+popHandler(); // key: from
+pushKey("repeat");
+addParameter([this](char const* p) { c_uo->repeat(p); });
+popHandler(); // key: repeat
+pushKey("to");
+addParameter([this](char const* p) { c_uo->to(p); });
+popHandler(); // key: to
+popHandler(); // key: overlay
+pushKey("underlay");
+beginDict(bindJSON(&Handlers::beginOptionsUnderlay), bindBare(&Handlers::endOptionsUnderlay)); // .options.underlay
+pushKey("file");
+setupOptionsUnderlayFile();
+popHandler(); // key: file
+pushKey("password");
+setupOptionsUnderlayPassword();
+popHandler(); // key: password
+pushKey("from");
+addParameter([this](char const* p) { c_uo->from(p); });
+popHandler(); // key: from
+pushKey("repeat");
+addParameter([this](char const* p) { c_uo->repeat(p); });
+popHandler(); // key: repeat
+pushKey("to");
+addParameter([this](char const* p) { c_uo->to(p); });
+popHandler(); // key: to
+popHandler(); // key: underlay
+popHandler(); // key: options
diff --git a/libqpdf/qpdf/auto_job_schema.hh b/libqpdf/qpdf/auto_job_schema.hh
index ba5c93df..2a621ac9 100644
--- a/libqpdf/qpdf/auto_job_schema.hh
+++ b/libqpdf/qpdf/auto_job_schema.hh
@@ -85,10 +85,10 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({
"showAttachment": "export an embedded file",
"json": "show file in json format",
"jsonKey": [
- null
+ "restrict which keys are in json output"
],
"jsonObject": [
- null
+ "restrict which objects are in JSON"
]
},
"options": {