aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xgenerate_auto_job149
-rw-r--r--job.sums8
-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
6 files changed, 612 insertions, 339 deletions
diff --git a/generate_auto_job b/generate_auto_job
index d935af8f..6b59debc 100755
--- a/generate_auto_job
+++ b/generate_auto_job
@@ -454,7 +454,7 @@ class Main:
identifier = self.to_identifier(table, 'argEnd', False)
self.decls.append(f'void {identifier}();')
- def handle_json_trivial(self, key, fdata):
+ def handle_json_trivial(self, flag_key, fdata):
config = None
for t, [kind, v] in fdata['tables'].items():
# We have determined that all tables, if multiple, have
@@ -463,106 +463,98 @@ class Main:
config = tdata['config']
if kind == 'bare':
self.json_init.append(
- f'addBare("{key}", [this]() {{ {config}->{key}(); }});')
+ f'addBare([this]() {{ {config}->{flag_key}(); }});')
elif kind == 'optional_parameter' or kind == 'required_parameter':
# No optional parameters in json
self.json_init.append(
- f'addParameter("{key}", [this](char const* p)'
- f' {{ {config}->{key}(p); }});')
+ f'addParameter([this](char const* p)'
+ f' {{ {config}->{flag_key}(p); }});')
elif kind == 'optional_choices' or kind == 'required_choices':
# No optional choices in json
self.json_init.append(
- f'addChoices("{key}", {v}_choices,'
- f' [this](char const* p) {{ {config}->{key}(p); }});')
+ f'addChoices({v}_choices,'
+ f' [this](char const* p) {{ {config}->{flag_key}(p); }});')
- def handle_json_manual(self, key, path):
+ def handle_json_manual(self, path):
method = re.sub(r'\.([a-zA-Z0-9])',
lambda x: x.group(1).upper(),
- f'setup{path}.{key}')
- self.json_decls.append(
- f'void {method}(std::string const&);')
- self.json_init.append(
- f'doSetup("{key}", bindSetup(&Handlers::{method}));')
+ f'setup{path}')
+ self.json_decls.append(f'void {method}();')
+ self.json_init.append(f'{method}();')
def option_to_json_key(self, s):
return self.to_identifier(s, '', False)
- def build_schema(self, j, s, flag, path, expected, options_seen):
- if flag:
+ def flag_to_schema_key(self, k):
+ if k.startswith('_'):
+ schema_key = k[1:]
+ else:
+ schema_key = re.sub(r'[^\.]+\.', '', k)
+ return self.option_to_json_key(schema_key)
+
+ def build_schema(self, j, path, flag, expected, options_seen):
+ if flag in expected:
+ options_seen.add(flag)
+ elif not (flag == '' or flag.startswith('_') or isinstance(j, str)):
+ raise Exception(f'json: unknown key {flag}')
+
+ if isinstance(j, dict):
+ schema_value = {}
+ if flag:
+ identifier = self.to_identifier(path, '', False)
+ self.json_decls.append(f'void begin{identifier}(JSON);')
+ self.json_decls.append(f'void end{identifier}();')
+ self.json_init.append(
+ f'beginDict(bindJSON(&Handlers::begin{identifier}),'
+ f' bindBare(&Handlers::end{identifier})); // {path}')
+ for k, v in j.items():
+ schema_key = self.flag_to_schema_key(k)
+ subpath = f'{path}.{schema_key}'
+ self.json_init.append(f'pushKey("{schema_key}");')
+ schema_value[schema_key] = self.build_schema(
+ v, subpath, k, expected, options_seen)
+ self.json_init.append(f'popHandler(); // key: {schema_key}')
+ elif isinstance(j, list):
+ if len(j) != 1:
+ raise Exception('json contains array with length != 1')
identifier = self.to_identifier(path, '', False)
- self.json_decls.append(f'void begin{identifier}(JSON);')
- self.json_decls.append(f'void end{identifier}();')
+ self.json_decls.append(f'void begin{identifier}Array(JSON);')
+ self.json_decls.append(f'void end{identifier}Array();')
+ self.json_init.append(
+ f'beginArray(bindJSON(&Handlers::begin{identifier}Array),'
+ f' bindBare(&Handlers::end{identifier}Array));'
+ f' // {path}[]')
+ schema_value = [
+ self.build_schema(j[0], path, flag,
+ expected, options_seen)
+ ]
self.json_init.append(
- f'beginDict("{flag}",'
- f' bindJSON(&Handlers::begin{identifier}),'
- f' bindBare(&Handlers::end{identifier})); // {path}')
- for k, v in j.items():
+ f'popHandler(); // array: {path}[]')
+ else:
+ schema_value = j
+ if schema_value is None:
+ schema_value = re.sub(
+ r'--(\S+)',
+ lambda x: self.option_to_json_key(x.group(1)),
+ expected[flag]['help'])
is_trivial = False
- if k in expected:
+ if flag in expected:
is_trivial = True
common_config = None
- for t in expected[k]['tables']:
+ for t in expected[flag]['tables']:
tdata = self.by_table[t]
- if k in tdata['manual']:
+ if flag in tdata['manual']:
is_trivial = False
if common_config is None:
common_config = tdata['config']
elif common_config != tdata['config']:
is_trivial = False
- elif not (k.startswith('_') or isinstance(v, str)):
- raise Exception(f'json: unknown key {k}')
- if k.startswith('_'):
- schema_key = k[1:]
+ config_key = self.flag_to_schema_key(flag)
+ if is_trivial:
+ self.handle_json_trivial(config_key, expected[flag])
else:
- schema_key = re.sub(r'[^\.]+\.', '', k)
- schema_key = self.option_to_json_key(schema_key)
- schema_value = v
- is_dict = False
- if k in expected:
- options_seen.add(re.sub('^_', '', k))
- if v is None:
- schema_value = re.sub(
- r'--(\S+)',
- lambda x: self.option_to_json_key(x.group(1)),
- expected[k]['help'])
- if (isinstance(v, dict)):
- is_dict = True
- schema_value = {}
- self.build_schema(v, schema_value,
- schema_key, f'{path}.{schema_key}',
- expected, options_seen)
- elif (isinstance(v, list)):
- if len(v) != 1:
- raise Exception('json contains array with length != 1')
- if isinstance(v[0], dict):
- is_dict = True
- schema_value = [{}]
- subpath = f'{path}.{schema_key}'
- identifier = self.to_identifier(subpath, '', False)
- self.json_decls.append(
- f'void begin{identifier}Array(JSON);')
- self.json_decls.append(
- f'void end{identifier}Array();')
- self.json_init.append(
- f'beginArray("{flag}",'
- f' bindJSON(&Handlers::begin{identifier}Array),'
- f' bindBare(&Handlers::end{identifier}Array));'
- f' // {subpath}[]')
- self.build_schema(v[0], schema_value[0],
- schema_key, subpath,
- expected, options_seen)
- self.json_init.append(
- f'endContainer(); // {subpath}[]')
- elif schema_value is None:
- raise Exception(f'unknown schema value for {k}')
- s[schema_key] = schema_value
- if not is_dict:
- if is_trivial:
- self.handle_json_trivial(schema_key, expected[k])
- else:
- self.handle_json_manual(schema_key, path)
- if flag:
- self.json_init.append(f'endContainer(); // {path}')
+ self.handle_json_manual(path)
+ return schema_value
def generate_schema(self, data):
# Check to make sure that every command-line option is
@@ -588,9 +580,8 @@ class Main:
# go. This verifies consistency between command-line options
# and the json section of the data and builds up a schema by
# populating with help information as available.
- self.schema = {}
- self.build_schema(data['json'], self.schema, '', '',
- expected, options_seen)
+ self.schema = self.build_schema(
+ data['json'], '', '', expected, options_seen)
if options_seen != set(expected.keys()):
raise Exception('missing from json: ' +
str(set(expected.keys()) - options_seen))
diff --git a/job.sums b/job.sums
index 2126ccf5..ee8f1bc0 100644
--- a/job.sums
+++ b/job.sums
@@ -1,5 +1,5 @@
# Generated by generate_auto_job
-generate_auto_job 8c88accfa988c8d6035c3e7e012bbde3da0c76fdfaba8e1460112bf344dc7b4f
+generate_auto_job e28f3fb4938f6307bb4c23c084c239832dbee3bbaedf19a22fb19215312b30b0
include/qpdf/auto_job_c_att.hh 7ad43bb374c1370ef32ebdcdcb7b73a61d281f7f4e3f12755585872ab30fb60e
include/qpdf/auto_job_c_copy_att.hh 32275d03cdc69b703dd7e02ba0bbe15756e714e9ad185484773a6178dc09e1ee
include/qpdf/auto_job_c_enc.hh 72e138c7b96ed5aacdce78c1dec04b1c20d361faec4f8faf52f64c1d6be99265
@@ -10,8 +10,8 @@ job.yml 14622557f5c96f379645f01c3d21b3d03bb8fd9c6062a3af429430d5348f5538
libqpdf/qpdf/auto_job_decl.hh 9f79396ec459f191be4c5fe34cf88c265cf47355a1a945fa39169d1c94cf04f6
libqpdf/qpdf/auto_job_help.hh 23c79f1d2c02bda28f64aace17f69487205c797e7ae2234892cbbabab49d6d47
libqpdf/qpdf/auto_job_init.hh 8e9e31b6099a662497339b27f6e2d7f779f35011e88a834bee8811c33405a0fe
-libqpdf/qpdf/auto_job_json_decl.hh f349b55cf85d07a28aeb4bef257bdbcbe16f76b8065d01154161897b1e0fa643
-libqpdf/qpdf/auto_job_json_init.hh 60d08982781bd568ab6083d325441f99a6bc39f72492558b8a64757373b2cfbe
-libqpdf/qpdf/auto_job_schema.hh a483911bb1fda9cca53f3021bcdf26998604eabb23f131c78055c52d33ff5a4f
+libqpdf/qpdf/auto_job_json_decl.hh 4846055075dcb7365c56c02150e955979b522d14f4329ce7a8a302ccd1d7aa2a
+libqpdf/qpdf/auto_job_json_init.hh a8053ffcd4cc8c533a269805c79bba6757e5d17800f0d18938adf16e896694a3
+libqpdf/qpdf/auto_job_schema.hh 3cd89b775118e09aa99fed200ca36c8a8dec8d17bc039012ca210b6a33ce1d8a
manual/_ext/qpdf.py e9ac9d6c70642a3d29281ee5ad92ae2422dee8be9306fb8a0bc9dba0ed5e28f3
manual/cli.rst 79140e023faa0cb77afe0b1dc512dd120ee5617f4db82f842596e4f239f93882
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": {