diff --git a/generate_auto_job b/generate_auto_job index 5b53ef55..3dea7792 100755 --- a/generate_auto_job +++ b/generate_auto_job @@ -364,16 +364,17 @@ class Main: self.json_decls = [] self.json_init = [] self.jdata = {} + self.by_table = {} - def add_jdata(flag, table): + def add_jdata(flag, table, details): nonlocal self if table == 'help': self.help_options.add(f'--{flag}') elif flag in self.jdata: - self.jdata[flag]['tables'].add(table) + self.jdata[flag]['tables'][table] = details else: self.jdata[flag] = { - 'tables': set([table]), + 'tables': {table: details}, } self.init.append('auto b = [this](void (ArgParser::*f)()) {') @@ -384,11 +385,14 @@ class Main: self.init.append('};') self.init.append('') for k, v in data['choices'].items(): - s = f'char const* {k}_choices[] = {{' + s = f'static char const* {k}_choices[] = {{' for i in v: s += f'"{i}", ' - self.init.append(s + '0};') + s += '0};' + self.init.append(s) + self.json_init.append(s) self.init.append('') + self.json_init.append('') for o in data['options']: table = o['table'] @@ -402,6 +406,13 @@ class Main: config = o.get('config', None) table_prefix = o.get('prefix', '') arg_prefix = 'arg' + table_prefix + config_prefix = o.get('config_prefix', table_prefix) + manual = o.get('manual', []) + json_prefix = table_prefix or table + self.by_table[json_prefix] = { + 'config': config, + 'manual': manual, + } if table == 'main': self.init.append('this->ap.selectMainOptionTable();') elif table == 'help': @@ -430,33 +441,58 @@ class Main: for i, [kind, v] in flags.items(): self.options_without_help.add(f'--{i}') - add_jdata(i, table_prefix or table) - if config is None or i in o.get('manual', []): + add_jdata(i, json_prefix, [kind, v]) + if config is None or i in manual: identifier = self.to_identifier(i, arg_prefix, False) self.handle_flag(i, identifier, kind, v) else: identifier = self.to_identifier(i, '', False) - prefix = o.get('config_prefix', table_prefix) self.handle_trivial( - i, identifier, config, prefix, kind, v) + i, identifier, config, config_prefix, kind, v) if table not in ('main', 'help'): identifier = self.to_identifier(table, 'argEnd', False) self.decls.append(f'void {identifier}();') - def generate_schema(self, data): - # XXX check data['json'] against what we know from jdata. - # Ultimately be able to generate a schema as well as - # JSONHandler and registering stuff. + def handle_json_trivial(self, key, fdata): + config = None + for t, [kind, v] in fdata['tables'].items(): + # We have determined that all tables, if multiple, have + # the same config. + tdata = self.by_table[t] + config = tdata['config'] + if kind == 'bare': + self.json_init.append( + f'addBare("{key}", [this]() {{ {config}->{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); }});') + 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); }});') + def handle_json_manual(self, key, 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}));') + + def generate_schema(self, data): # Check to make sure that every command-line option is # represented either in data['json'] or data['no-json']. # Build a list of options that we expect. If an option appears # once, we just expect to see it once. If it appears in more # than one options table, we need to see a separate version of - # it for each option table. It is represented prepended in - # job.yml with the table prefix. The table prefix is removed + # it for each option table. It is represented in job.yml + # prepended with the table prefix. The table prefix is removed # in the schema. expected = {} for k, v in self.jdata.items(): @@ -466,8 +502,6 @@ class Main: else: for t in sorted(tables): expected[f'{t}.{k}'] = {**v} - for _, v in expected.items(): - del v['tables'] options_seen = set(data['no-json']) self.schema = {} @@ -479,11 +513,29 @@ 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. - def build_schema(j, s): + def build_schema(j, s, flag, path): + if flag: + identifier = self.to_identifier(path, '', False) + self.json_decls.append(f'void begin{identifier}();') + self.json_decls.append(f'void end{identifier}();') + self.json_init.append( + f'beginDict("{flag}",' + f' bindBare(&Handlers::begin{identifier}),' + f' bindBare(&Handlers::end{identifier})); // {path}') for k, v in j.items(): - if not (k in expected or - k.startswith('_') or - isinstance(v, str)): + is_trivial = False + if k in expected: + is_trivial = True + common_config = None + for t in expected[k]['tables']: + tdata = self.by_table[t] + if k 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:] @@ -491,6 +543,7 @@ class Main: schema_key = re.sub(r'[^\.]+\.', '', k) schema_key = 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: @@ -499,19 +552,30 @@ class Main: lambda x: option_to_json_key(x.group(1)), expected[k]['help']) if (isinstance(v, dict)): + is_dict = True schema_value = {} - build_schema(v, schema_value) + build_schema(v, schema_value, + schema_key, f'{path}.{schema_key}') 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 = [{}] - build_schema(v[0], schema_value[0]) + build_schema(v[0], schema_value[0], + schema_key, f'{path}.{schema_key}') 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'endDict(); // {path}') - build_schema(data['json'], self.schema) + build_schema(data['json'], self.schema, '', '') if options_seen != set(expected.keys()): raise Exception('missing from json: ' + str(set(expected.keys()) - options_seen)) @@ -540,9 +604,7 @@ class Main: identifier = f'{prefix}_{identifier.upper()}' else: if prefix: - identifier = f'{prefix}_{identifier.lower()}' - else: - identifier = identifier.lower() + identifier = f'{prefix}_{identifier}' identifier = re.sub(r'_([a-z])', lambda x: x.group(1).upper(), identifier).replace('_', '') diff --git a/job.sums b/job.sums index fc0edb41..00c1dd4b 100644 --- a/job.sums +++ b/job.sums @@ -1,17 +1,17 @@ # Generated by generate_auto_job -generate_auto_job f9aa6ddc529f5be910566a59329d1d2fea7d18c7e5c014fe30f6567a3bd518aa +generate_auto_job 53b2b81e8cb38f1bfa0053f351f37fe9e9437eb2cef808ff0c01cfc56ca20946 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 include/qpdf/auto_job_c_main.hh 516adb23cc7e44e614e436880be870d0574e4ebbc706cd855a1360000eed31bb include/qpdf/auto_job_c_pages.hh 931840b329a36ca0e41401190e04537b47f2867671a6643bfd8da74014202671 include/qpdf/auto_job_c_uo.hh 0585b7de459fa479d9e51a45fa92de0ff6dee748efc9ec1cedd0dde6cee1ad50 -job.yml 1590fd16fd17ed40db9aa56b6713c844cfd61b3a6d0441a3ccd122b7371c68e9 +job.yml d9be74c397e1f272ac6a81981a528c332f8bd7b98d58ae6ba6f60875391567e8 libqpdf/qpdf/auto_job_decl.hh 9f79396ec459f191be4c5fe34cf88c265cf47355a1a945fa39169d1c94cf04f6 libqpdf/qpdf/auto_job_help.hh 23c79f1d2c02bda28f64aace17f69487205c797e7ae2234892cbbabab49d6d47 -libqpdf/qpdf/auto_job_init.hh 3b6323189480a7d782563c9d2b5bc29b8dcd19c6dcc89840b207e38cb503d3f1 -libqpdf/qpdf/auto_job_json_decl.hh 931840b329a36ca0e41401190e04537b47f2867671a6643bfd8da74014202671 -libqpdf/qpdf/auto_job_json_init.hh 931840b329a36ca0e41401190e04537b47f2867671a6643bfd8da74014202671 -libqpdf/qpdf/auto_job_schema.hh 1c3b4b5488270f8d200ed345573e3a241f15baff6fb7e97ec3d044103b2546d9 +libqpdf/qpdf/auto_job_init.hh 8e9e31b6099a662497339b27f6e2d7f779f35011e88a834bee8811c33405a0fe +libqpdf/qpdf/auto_job_json_decl.hh d729213332b92ee0da89d1cad0318ab96aec443f37d208fbbc8d56e9d1398ac2 +libqpdf/qpdf/auto_job_json_init.hh a28c2c2b83d1c0036d3d07172dffb1eac1b75ce3d6a615a87111e9f3bd3dad58 +libqpdf/qpdf/auto_job_schema.hh 9962f09f3260c01d4165a6ddf2814a0621395dcb5d80a3d310f580a1b7d3baba manual/_ext/qpdf.py e9ac9d6c70642a3d29281ee5ad92ae2422dee8be9306fb8a0bc9dba0ed5e28f3 manual/cli.rst 79140e023faa0cb77afe0b1dc512dd120ee5617f4db82f842596e4f239f93882 diff --git a/job.yml b/job.yml index 4709e9d0..3ad65a70 100644 --- a/job.yml +++ b/job.yml @@ -253,16 +253,13 @@ json: # a "schema" (as in JSON.hh) for the json input to QPDFJob. The # leading underscore is removed. _input: - # QXXXQ need to figure out how to specify input and output - _file: - _name: "input filename" - main.password: - password-file: - _empty: "qxxxq empty" + _fileName: "input filename" + main.password: + password-file: + empty: _output: - _file: - _name: "output filename" - _replace-input: "qxxxq replace input" + _fileName: "output filename" + _replace-input: "set to true to replace input" _options: qdf: preserve-unreferenced: diff --git a/libqpdf/QPDFJob_json.cc b/libqpdf/QPDFJob_json.cc index 0b2f049c..735e6a6f 100644 --- a/libqpdf/QPDFJob_json.cc +++ b/libqpdf/QPDFJob_json.cc @@ -23,20 +23,23 @@ namespace void usage(std::string const& message); void initHandlers(); - typedef std::function bare_arg_handler_t; - typedef std::function param_arg_handler_t; + typedef std::function bare_handler_t; + typedef std::function param_handler_t; + typedef std::function setup_handler_t; - void addBare(std::string const& key, bare_arg_handler_t); - void addParameter(std::string const& key, bool required, - param_arg_handler_t); - void addChoices(std::string const& key, - bool required, char const** choices, - param_arg_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, - bare_arg_handler_t start_fn, - bare_arg_handler_t end_fn); + bare_handler_t start_fn, + bare_handler_t end_fn); void endDict(); + bare_handler_t bindBare(void (Handlers::*f)()); + setup_handler_t bindSetup(void (Handlers::*f)(std::string const&)); + std::list> json_handlers; JSONHandler* jh; // points to last of json_handlers std::shared_ptr c_main; @@ -61,6 +64,18 @@ Handlers::usage(std::string const& message) throw QPDFUsage(message); } +Handlers::bare_handler_t +Handlers::bindBare(void (Handlers::*f)()) +{ + return std::bind(std::mem_fn(f), this); +} + +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() { @@ -72,33 +87,6 @@ Handlers::initHandlers() # include - // QXXXQ - auto empty = [](){}; - beginDict("input", empty, empty); - beginDict("file", empty, empty); - addParameter("name", true, [this](char const* p) { - c_main->inputFile(p); - }); - endDict(); // input.file - endDict(); // input - beginDict("output", empty, empty); - beginDict("file", empty, empty); - addParameter("name", true, [this](char const* p) { - c_main->outputFile(p); - }); - endDict(); // output.file - beginDict("options", empty, empty); - addBare("qdf", [this]() { - c_main->qdf(); - }); - char const* choices[] = {"disable", "preserve", "generate", 0}; - addChoices("objectStreams", true, choices, [this](char const* p) { - c_main->objectStreams(p); - }); - endDict(); // output.options - endDict(); // output - // /QXXXQ - if (this->json_handlers.size() != 1) { throw std::logic_error("QPDFJob_json: json_handlers size != 1 at end"); @@ -106,7 +94,7 @@ Handlers::initHandlers() } void -Handlers::addBare(std::string const& key, bare_arg_handler_t fn) +Handlers::addBare(std::string const& key, bare_handler_t fn) { auto h = std::make_shared(); h->addBoolHandler([this, fn](std::string const& path, bool v){ @@ -123,29 +111,19 @@ Handlers::addBare(std::string const& key, bare_arg_handler_t fn) } void -Handlers::addParameter(std::string const& key, - bool required, - param_arg_handler_t fn) +Handlers::addParameter(std::string const& key, param_handler_t fn) { auto h = std::make_shared(); h->addStringHandler( [fn](std::string const& path, std::string const& parameter){ fn(parameter.c_str()); }); - if (! required) - { - h->addNullHandler( - [fn](std::string const& path){ - fn(nullptr); - }); - } jh->addDictKeyHandler(key, h); } void -Handlers::addChoices(std::string const& key, - bool required, char const** choices, - param_arg_handler_t fn) +Handlers::addChoices(std::string const& key, char const** choices, + param_handler_t fn) { auto h = std::make_shared(); h->addStringHandler( @@ -183,20 +161,19 @@ Handlers::addChoices(std::string const& key, } fn(parameter.c_str()); }); - if (! required) - { - h->addNullHandler( - [fn](std::string const& path){ - fn(nullptr); - }); - } jh->addDictKeyHandler(key, h); } +void +Handlers::doSetup(std::string const& key, setup_handler_t fn) +{ + fn(key); +} + void Handlers::beginDict(std::string const& key, - bare_arg_handler_t start_fn, - bare_arg_handler_t end_fn) + bare_handler_t start_fn, + bare_handler_t end_fn) { auto new_jh = std::make_shared(); new_jh->addDictHandlers( @@ -220,6 +197,314 @@ Handlers::handle(JSON& j) this->json_handlers.back()->handle(".", j); } +void +Handlers::beginInput() +{ + // nothing needed +} + +void +Handlers::endInput() +{ + // nothing needed +} + +void +Handlers::setupInputFileName(std::string const& key) +{ + addParameter(key, [this](char const* p) { + c_main->inputFile(p); + }); +} + +void +Handlers::setupInputPassword(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::setupInputEmpty(std::string const& key) +{ + addBare(key, [this]() { + c_main->emptyInput(); + }); +} + +void +Handlers::beginOutput() +{ + // nothing needed +} + +void +Handlers::endOutput() +{ + // nothing needed +} + +void +Handlers::setupOutputFileName(std::string const& key) +{ + addParameter(key, [this](char const* p) { + c_main->outputFile(p); + }); +} + +void +Handlers::setupOutputReplaceInput(std::string const& key) +{ + addBare(key, [this]() { + c_main->replaceInput(); + }); +} + +void +Handlers::beginOutputOptions() +{ + // nothing needed +} + +void +Handlers::endOutputOptions() +{ + // nothing needed +} + +void +Handlers::beginOutputOptionsEncrypt() +{ + // QXXXQ +} + +void +Handlers::endOutputOptionsEncrypt() +{ + // QXXXQ +} + +void +Handlers::setupOutputOptionsEncryptKeyLength(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::setupOutputOptionsEncryptUserPassword(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::setupOutputOptionsEncryptOwnerPassword(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::beginOutputOptionsEncrypt40Bit() +{ + // QXXXQ +} + +void +Handlers::endOutputOptionsEncrypt40Bit() +{ + // QXXXQ +} + +void +Handlers::beginOutputOptionsEncrypt128Bit() +{ + // QXXXQ +} + +void +Handlers::endOutputOptionsEncrypt128Bit() +{ + // QXXXQ +} + +void +Handlers::beginOutputOptionsEncrypt256Bit() +{ + // QXXXQ +} + +void +Handlers::endOutputOptionsEncrypt256Bit() +{ + // QXXXQ +} + +void +Handlers::beginOptions() +{ + // nothing needed +} + +void +Handlers::endOptions() +{ + // nothing needed +} + +void +Handlers::beginInspect() +{ + // nothing needed +} + +void +Handlers::endInspect() +{ + // nothing needed +} + +void +Handlers::beginTransform() +{ + // nothing needed +} + +void +Handlers::endTransform() +{ + // nothing needed +} + +void +Handlers::beginModify() +{ + // nothing needed +} + +void +Handlers::endModify() +{ + // nothing needed +} + +void +Handlers::beginModifyAddAttachment() +{ + // QXXXQ +} + +void +Handlers::endModifyAddAttachment() +{ + // QXXXQ +} + +void +Handlers::setupModifyAddAttachmentPath(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::beginModifyCopyAttachmentsFrom() +{ + // QXXXQ +} + +void +Handlers::endModifyCopyAttachmentsFrom() +{ + // QXXXQ +} + +void +Handlers::setupModifyCopyAttachmentsFromPath(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::setupModifyCopyAttachmentsFromPassword(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::beginModifyPages() +{ + // QXXXQ +} + +void +Handlers::endModifyPages() +{ + // QXXXQ +} + +void +Handlers::setupModifyPagesFile(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::setupModifyPagesPassword(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::setupModifyPagesRange(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::beginModifyOverlay() +{ + // QXXXQ +} + +void +Handlers::endModifyOverlay() +{ + // QXXXQ +} + +void +Handlers::setupModifyOverlayFile(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::setupModifyOverlayPassword(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::beginModifyUnderlay() +{ + // QXXXQ +} + +void +Handlers::endModifyUnderlay() +{ + // QXXXQ +} + +void +Handlers::setupModifyUnderlayFile(std::string const& key) +{ + // QXXXQ +} + +void +Handlers::setupModifyUnderlayPassword(std::string const& key) +{ + // QXXXQ +} + void QPDFJob::initializeFromJson(std::string const& json) { diff --git a/libqpdf/qpdf/auto_job_init.hh b/libqpdf/qpdf/auto_job_init.hh index b6750f43..79fdc6d3 100644 --- a/libqpdf/qpdf/auto_job_init.hh +++ b/libqpdf/qpdf/auto_job_init.hh @@ -10,16 +10,16 @@ auto p = [this](void (ArgParser::*f)(char *)) { return QPDFArgParser::bindParam(f, this); }; -char const* yn_choices[] = {"y", "n", 0}; -char const* password_mode_choices[] = {"bytes", "hex-bytes", "unicode", "auto", 0}; -char const* stream_data_choices[] = {"compress", "preserve", "uncompress", 0}; -char const* decode_level_choices[] = {"none", "generalized", "specialized", "all", 0}; -char const* object_streams_choices[] = {"disable", "preserve", "generate", 0}; -char const* remove_unref_choices[] = {"auto", "yes", "no", 0}; -char const* flatten_choices[] = {"all", "print", "screen", 0}; -char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "objectinfo", "objects", "outlines", "pagelabels", "pages", 0}; -char const* print128_choices[] = {"full", "low", "none", 0}; -char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0}; +static char const* yn_choices[] = {"y", "n", 0}; +static char const* password_mode_choices[] = {"bytes", "hex-bytes", "unicode", "auto", 0}; +static char const* stream_data_choices[] = {"compress", "preserve", "uncompress", 0}; +static char const* decode_level_choices[] = {"none", "generalized", "specialized", "all", 0}; +static char const* object_streams_choices[] = {"disable", "preserve", "generate", 0}; +static char const* remove_unref_choices[] = {"auto", "yes", "no", 0}; +static char const* flatten_choices[] = {"all", "print", "screen", 0}; +static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "objectinfo", "objects", "outlines", "pagelabels", "pages", 0}; +static char const* print128_choices[] = {"full", "low", "none", 0}; +static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0}; this->ap.selectHelpOptionTable(); this->ap.addBare("version", b(&ArgParser::argVersion)); diff --git a/libqpdf/qpdf/auto_job_json_decl.hh b/libqpdf/qpdf/auto_job_json_decl.hh index d6cbecfe..817eff7c 100644 --- a/libqpdf/qpdf/auto_job_json_decl.hh +++ b/libqpdf/qpdf/auto_job_json_decl.hh @@ -3,3 +3,53 @@ // Edits will be automatically overwritten if the build is // run in maintainer mode. // +void beginInput(); +void endInput(); +void setupInputFileName(std::string const&); +void setupInputPassword(std::string const&); +void setupInputEmpty(std::string const&); +void beginOutput(); +void endOutput(); +void setupOutputFileName(std::string const&); +void setupOutputReplaceInput(std::string const&); +void beginOutputOptions(); +void endOutputOptions(); +void beginOutputOptionsEncrypt(); +void endOutputOptionsEncrypt(); +void setupOutputOptionsEncryptKeyLength(std::string const&); +void setupOutputOptionsEncryptUserPassword(std::string const&); +void setupOutputOptionsEncryptOwnerPassword(std::string const&); +void beginOutputOptionsEncrypt40Bit(); +void endOutputOptionsEncrypt40Bit(); +void beginOutputOptionsEncrypt128Bit(); +void endOutputOptionsEncrypt128Bit(); +void beginOutputOptionsEncrypt256Bit(); +void endOutputOptionsEncrypt256Bit(); +void beginOptions(); +void endOptions(); +void beginInspect(); +void endInspect(); +void beginTransform(); +void endTransform(); +void beginModify(); +void endModify(); +void beginModifyAddAttachment(); +void endModifyAddAttachment(); +void setupModifyAddAttachmentPath(std::string const&); +void beginModifyCopyAttachmentsFrom(); +void endModifyCopyAttachmentsFrom(); +void setupModifyCopyAttachmentsFromPath(std::string const&); +void setupModifyCopyAttachmentsFromPassword(std::string const&); +void beginModifyPages(); +void endModifyPages(); +void setupModifyPagesFile(std::string const&); +void setupModifyPagesPassword(std::string const&); +void setupModifyPagesRange(std::string const&); +void beginModifyOverlay(); +void endModifyOverlay(); +void setupModifyOverlayFile(std::string const&); +void setupModifyOverlayPassword(std::string const&); +void beginModifyUnderlay(); +void endModifyUnderlay(); +void setupModifyUnderlayFile(std::string const&); +void setupModifyUnderlayPassword(std::string const&); diff --git a/libqpdf/qpdf/auto_job_json_init.hh b/libqpdf/qpdf/auto_job_json_init.hh index d6cbecfe..2ffd2ee7 100644 --- a/libqpdf/qpdf/auto_job_json_init.hh +++ b/libqpdf/qpdf/auto_job_json_init.hh @@ -3,3 +3,174 @@ // Edits will be automatically overwritten if the build is // run in maintainer mode. // +static char const* yn_choices[] = {"y", "n", 0}; +static char const* password_mode_choices[] = {"bytes", "hex-bytes", "unicode", "auto", 0}; +static char const* stream_data_choices[] = {"compress", "preserve", "uncompress", 0}; +static char const* decode_level_choices[] = {"none", "generalized", "specialized", "all", 0}; +static char const* object_streams_choices[] = {"disable", "preserve", "generate", 0}; +static char const* remove_unref_choices[] = {"auto", "yes", "no", 0}; +static char const* flatten_choices[] = {"all", "print", "screen", 0}; +static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "objectinfo", "objects", "outlines", "pagelabels", "pages", 0}; +static char const* print128_choices[] = {"full", "low", "none", 0}; +static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0}; + +beginDict("input", bindBare(&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)); +endDict(); // .input +beginDict("output", bindBare(&Handlers::beginOutput), bindBare(&Handlers::endOutput)); // .output +doSetup("fileName", bindSetup(&Handlers::setupOutputFileName)); +doSetup("replaceInput", bindSetup(&Handlers::setupOutputReplaceInput)); +beginDict("options", bindBare(&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", bindBare(&Handlers::beginOutputOptionsEncrypt), bindBare(&Handlers::endOutputOptionsEncrypt)); // .output.options.encrypt +doSetup("keyLength", bindSetup(&Handlers::setupOutputOptionsEncryptKeyLength)); +doSetup("userPassword", bindSetup(&Handlers::setupOutputOptionsEncryptUserPassword)); +doSetup("ownerPassword", bindSetup(&Handlers::setupOutputOptionsEncryptOwnerPassword)); +beginDict("40Bit", bindBare(&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); }); +endDict(); // .output.options.encrypt.40Bit +beginDict("128Bit", bindBare(&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); }); +endDict(); // .output.options.encrypt.128Bit +beginDict("256Bit", bindBare(&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(); }); +endDict(); // .output.options.encrypt.256Bit +endDict(); // .output.options.encrypt +endDict(); // .output.options +endDict(); // .output +beginDict("options", bindBare(&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("warningExit0", [this]() { c_main->warningExit0(); }); +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(); }); +endDict(); // .options +beginDict("inspect", bindBare(&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("isEncrypted", [this]() { c_main->isEncrypted(); }); +addBare("rawStreamData", [this]() { c_main->rawStreamData(); }); +addBare("requiresPassword", [this]() { c_main->requiresPassword(); }); +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); }); +endDict(); // .inspect +beginDict("transform", bindBare(&Handlers::beginTransform), bindBare(&Handlers::endTransform)); // .transform +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); }); +endDict(); // .transform +beginDict("modify", bindBare(&Handlers::beginModify), bindBare(&Handlers::endModify)); // .modify +beginDict("addAttachment", bindBare(&Handlers::beginModifyAddAttachment), bindBare(&Handlers::endModifyAddAttachment)); // .modify.addAttachment +doSetup("path", bindSetup(&Handlers::setupModifyAddAttachmentPath)); +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(); }); +endDict(); // .modify.addAttachment +addParameter("removeAttachment", [this](char const* p) { c_main->removeAttachment(p); }); +beginDict("copyAttachmentsFrom", bindBare(&Handlers::beginModifyCopyAttachmentsFrom), bindBare(&Handlers::endModifyCopyAttachmentsFrom)); // .modify.copyAttachmentsFrom +doSetup("path", bindSetup(&Handlers::setupModifyCopyAttachmentsFromPath)); +doSetup("password", bindSetup(&Handlers::setupModifyCopyAttachmentsFromPassword)); +addParameter("prefix", [this](char const* p) { c_copy_att->prefix(p); }); +endDict(); // .modify.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(); }); +beginDict("pages", bindBare(&Handlers::beginModifyPages), bindBare(&Handlers::endModifyPages)); // .modify.pages +doSetup("file", bindSetup(&Handlers::setupModifyPagesFile)); +doSetup("password", bindSetup(&Handlers::setupModifyPagesPassword)); +doSetup("range", bindSetup(&Handlers::setupModifyPagesRange)); +endDict(); // .modify.pages +addBare("removePageLabels", [this]() { c_main->removePageLabels(); }); +addParameter("rotate", [this](char const* p) { c_main->rotate(p); }); +beginDict("overlay", bindBare(&Handlers::beginModifyOverlay), bindBare(&Handlers::endModifyOverlay)); // .modify.overlay +doSetup("file", bindSetup(&Handlers::setupModifyOverlayFile)); +doSetup("password", bindSetup(&Handlers::setupModifyOverlayPassword)); +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); }); +endDict(); // .modify.overlay +beginDict("underlay", bindBare(&Handlers::beginModifyUnderlay), bindBare(&Handlers::endModifyUnderlay)); // .modify.underlay +doSetup("file", bindSetup(&Handlers::setupModifyUnderlayFile)); +doSetup("password", bindSetup(&Handlers::setupModifyUnderlayPassword)); +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); }); +endDict(); // .modify.underlay +endDict(); // .modify diff --git a/libqpdf/qpdf/auto_job_schema.hh b/libqpdf/qpdf/auto_job_schema.hh index 53356d66..968a6754 100644 --- a/libqpdf/qpdf/auto_job_schema.hh +++ b/libqpdf/qpdf/auto_job_schema.hh @@ -1,17 +1,13 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({ "input": { - "file": { - "name": "input filename", - "password": "specify password", - "passwordFile": "read password from a file" - }, - "empty": "qxxxq empty" + "fileName": "input filename", + "password": "specify password", + "passwordFile": "read password from a file", + "empty": "empty input file" }, "output": { - "file": { - "name": "output filename" - }, - "replaceInput": "qxxxq replace input", + "fileName": "output filename", + "replaceInput": "set to true to replace input", "options": { "qdf": "enable viewing PDF code in a text editor", "preserveUnreferenced": "preserve unreferenced objects",