Commit 1d6da60048b3984565b09172cddb9f83949ccb45
1 parent
e2823965
Expose global settings in `QPDFJob` / the CLI
Showing
26 changed files
with
693 additions
and
24 deletions
include/qpdf/QPDFJob.hh
| @@ -306,6 +306,24 @@ class QPDFJob | @@ -306,6 +306,24 @@ class QPDFJob | ||
| 306 | Config* config; | 306 | Config* config; |
| 307 | }; | 307 | }; |
| 308 | 308 | ||
| 309 | + class GlobalConfig | ||
| 310 | + { | ||
| 311 | + friend class QPDFJob; | ||
| 312 | + friend class Config; | ||
| 313 | + | ||
| 314 | + public: | ||
| 315 | + QPDF_DLL | ||
| 316 | + Config* endGlobal(); | ||
| 317 | + | ||
| 318 | +#include <qpdf/auto_job_c_global.hh> | ||
| 319 | + | ||
| 320 | + GlobalConfig(Config*); // for qpdf internal use only | ||
| 321 | + GlobalConfig(GlobalConfig const&) = delete; | ||
| 322 | + | ||
| 323 | + private: | ||
| 324 | + Config* config; | ||
| 325 | + }; | ||
| 326 | + | ||
| 309 | class Config | 327 | class Config |
| 310 | { | 328 | { |
| 311 | friend class QPDFJob; | 329 | friend class QPDFJob; |
| @@ -331,6 +349,8 @@ class QPDFJob | @@ -331,6 +349,8 @@ class QPDFJob | ||
| 331 | QPDF_DLL | 349 | QPDF_DLL |
| 332 | std::shared_ptr<AttConfig> addAttachment(); | 350 | std::shared_ptr<AttConfig> addAttachment(); |
| 333 | QPDF_DLL | 351 | QPDF_DLL |
| 352 | + std::shared_ptr<GlobalConfig> global(); | ||
| 353 | + QPDF_DLL | ||
| 334 | std::shared_ptr<PagesConfig> pages(); | 354 | std::shared_ptr<PagesConfig> pages(); |
| 335 | QPDF_DLL | 355 | QPDF_DLL |
| 336 | std::shared_ptr<UOConfig> overlay(); | 356 | std::shared_ptr<UOConfig> overlay(); |
include/qpdf/auto_job_c_global.hh
0 โ 100644
| 1 | +// | ||
| 2 | +// This file is automatically generated by generate_auto_job. | ||
| 3 | +// Edits will be automatically overwritten if the build is | ||
| 4 | +// run in maintainer mode. | ||
| 5 | +// | ||
| 6 | +// clang-format off | ||
| 7 | +// | ||
| 8 | +QPDF_DLL GlobalConfig* noDefaultLimits(); | ||
| 9 | +QPDF_DLL GlobalConfig* parserMaxContainerSize(std::string const& parameter); | ||
| 10 | +QPDF_DLL GlobalConfig* parserMaxContainerSizeDamaged(std::string const& parameter); | ||
| 11 | +QPDF_DLL GlobalConfig* parserMaxErrors(std::string const& parameter); | ||
| 12 | +QPDF_DLL GlobalConfig* parserMaxNesting(std::string const& parameter); |
include/qpdf/auto_job_c_limits.hh
0 โ 100644
include/qpdf/global.hh
| @@ -145,7 +145,7 @@ namespace qpdf::global | @@ -145,7 +145,7 @@ namespace qpdf::global | ||
| 145 | set_uint32(qpdf_p_parser_max_errors, value); | 145 | set_uint32(qpdf_p_parser_max_errors, value); |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | - /// @brief Retrieves the maximum number of objectstop-level allowed in a container while | 148 | + /// @brief Retrieves the maximum number of top-level objects allowed in a container while |
| 149 | /// parsing. | 149 | /// parsing. |
| 150 | /// | 150 | /// |
| 151 | /// The limit applies when the PDF document's xref table is undamaged and the object itself | 151 | /// The limit applies when the PDF document's xref table is undamaged and the object itself |
| @@ -160,7 +160,8 @@ namespace qpdf::global | @@ -160,7 +160,8 @@ namespace qpdf::global | ||
| 160 | return get_uint32(qpdf_p_parser_max_container_size); | 160 | return get_uint32(qpdf_p_parser_max_container_size); |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | - /// @brief Sets the maximum number oftop-level objects allowed in a container while parsing. | 163 | + /// @brief Sets the maximum number of top-level objects allowed in a container while |
| 164 | + /// parsing. | ||
| 164 | /// | 165 | /// |
| 165 | /// The limit applies when the PDF document's xref table is undamaged and the object itself | 166 | /// The limit applies when the PDF document's xref table is undamaged and the object itself |
| 166 | /// can be parsed without errors. The default limit is 4,294,967,295. | 167 | /// can be parsed without errors. The default limit is 4,294,967,295. |
| @@ -178,8 +179,7 @@ namespace qpdf::global | @@ -178,8 +179,7 @@ namespace qpdf::global | ||
| 178 | /// parsing objects. | 179 | /// parsing objects. |
| 179 | /// | 180 | /// |
| 180 | /// The limit applies when the PDF document's xref table is damaged or the object itself is | 181 | /// The limit applies when the PDF document's xref table is damaged or the object itself is |
| 181 | - /// damaged. The limit also applies when parsing trailer dictionaries and xref streams. The | ||
| 182 | - /// default limit is 5,000. | 182 | + /// damaged. The limit also applies when parsing xref streams. The default limit is 5,000. |
| 183 | /// | 183 | /// |
| 184 | /// @return The maximum number of top-level objects allowed in a container while parsing | 184 | /// @return The maximum number of top-level objects allowed in a container while parsing |
| 185 | /// objects. | 185 | /// objects. |
job.sums
| @@ -4,17 +4,18 @@ generate_auto_job 8e3175a515aa8837d8a01bba0346b04b3d777d70330ba5b7d52f691316054a | @@ -4,17 +4,18 @@ generate_auto_job 8e3175a515aa8837d8a01bba0346b04b3d777d70330ba5b7d52f691316054a | ||
| 4 | include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 | 4 | include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 |
| 5 | include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 | 5 | include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 |
| 6 | include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5 | 6 | include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5 |
| 7 | +include/qpdf/auto_job_c_global.hh f1dc365206d033a0d6b19b6e561cc244fbd5b49a8d9604b5b646a5fd92895a5a | ||
| 7 | include/qpdf/auto_job_c_main.hh b865eb827356554763bb8349eadfcbc5cb260f80e025a5e229467c525007356d | 8 | include/qpdf/auto_job_c_main.hh b865eb827356554763bb8349eadfcbc5cb260f80e025a5e229467c525007356d |
| 8 | include/qpdf/auto_job_c_pages.hh 09ca15649cc94fdaf6d9bdae28a20723f2a66616bf15aa86d83df31051d82506 | 9 | include/qpdf/auto_job_c_pages.hh 09ca15649cc94fdaf6d9bdae28a20723f2a66616bf15aa86d83df31051d82506 |
| 9 | include/qpdf/auto_job_c_uo.hh 9c2f98a355858dd54d0bba444b73177a59c9e56833e02fa6406f429c07f39e62 | 10 | include/qpdf/auto_job_c_uo.hh 9c2f98a355858dd54d0bba444b73177a59c9e56833e02fa6406f429c07f39e62 |
| 10 | -job.yml e136726a6c7e43736b1f75f4de347fa50baf5f38ed1da58647ce2e980751fb29 | ||
| 11 | -libqpdf/qpdf/auto_job_decl.hh 34ba07d3891c3e5cdd8712f991e508a0652c9db314c5d5bcdf4421b76e6f6e01 | ||
| 12 | -libqpdf/qpdf/auto_job_help.hh d0cca031e99f10caa3f4b70ea574b36b0af63d24de333e7d6f0bf835e959f0be | ||
| 13 | -libqpdf/qpdf/auto_job_init.hh 02c526c37ad4051cac956ac7c12ae1d020517264f3f3d3beabb066ae2529e4bf | ||
| 14 | -libqpdf/qpdf/auto_job_json_decl.hh 04965f6321e54b8b3b1dd2ca101d763a22ab44fa81c69e4b6fc0fd6bb7f50f92 | ||
| 15 | -libqpdf/qpdf/auto_job_json_init.hh b49378f00d521a9f3e0ce9086e30b082bc6ef8e43c845e2a3c99857b72448307 | ||
| 16 | -libqpdf/qpdf/auto_job_schema.hh f6a3e8b663714bba50b594f5e31437bbcb96ca4609d2c150c3bbc172e3b000fa | 11 | +job.yml 131922d22086d9f4710743e18229cc1e956268197bcae8e1aae30f3be42877be |
| 12 | +libqpdf/qpdf/auto_job_decl.hh d612a02839e4f20a80e1c6a3ba09c17187fccddc3581ec7ebb1e3919ffd6801d | ||
| 13 | +libqpdf/qpdf/auto_job_help.hh 00ac90c621b6c0529d7bad9ea596f57595517901c8d33f49d2812fbea52dfb41 | ||
| 14 | +libqpdf/qpdf/auto_job_init.hh 889dde948e0ab53616584976d9520ab7ab3773c787d241f8a107f5e2f9f2112f | ||
| 15 | +libqpdf/qpdf/auto_job_json_decl.hh 7dbb83ddadcea39bfd1faa4ca061e1e3c3134d693b8ae634b463e7e19dc8bd0a | ||
| 16 | +libqpdf/qpdf/auto_job_json_init.hh 3c5f3d07a85e89dd7ecd79342c18e1f0ad580fc57758abb434aa9c9ae277c01e | ||
| 17 | +libqpdf/qpdf/auto_job_schema.hh eb21c99d3a4dc40b333fd1b19d5de52f8813c74a1d4ca830ea4c3311c120d63e | ||
| 17 | manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 | 18 | manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 |
| 18 | -manual/cli.rst b7bd5e34495d3f9156ff6242988dba73a2e5dce33d71f75ec1415514a3843f35 | ||
| 19 | -manual/qpdf.1 d5785d23e77b02a77180419d87787002dc244d82d586d56008ab603299f565fd | 19 | +manual/cli.rst 08e9e7a18d2b0d05102a072f82eabf9ede6bfb1fb797be307ea680eed93ea60f |
| 20 | +manual/qpdf.1 19a45f8de6b7c0584fe4395c4ae98b92147a2875e45dbdf729c70e644ccca295 | ||
| 20 | manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b | 21 | manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b |
job.yml
| @@ -84,12 +84,24 @@ options: | @@ -84,12 +84,24 @@ options: | ||
| 84 | - zopfli | 84 | - zopfli |
| 85 | optional_choices: | 85 | optional_choices: |
| 86 | json-help: json_version | 86 | json-help: json_version |
| 87 | + - table: global | ||
| 88 | + prefix: Global | ||
| 89 | + config: c_global | ||
| 90 | + positional: false | ||
| 91 | + bare: | ||
| 92 | + - no-default-limits | ||
| 93 | + required_parameter: | ||
| 94 | + parser-max-container-size: level | ||
| 95 | + parser-max-container-size-damaged: level | ||
| 96 | + parser-max-errors: level | ||
| 97 | + parser-max-nesting: level | ||
| 87 | - table: main | 98 | - table: main |
| 88 | config: c_main | 99 | config: c_main |
| 89 | manual: | 100 | manual: |
| 90 | - add-attachment | 101 | - add-attachment |
| 91 | - copy-attachments-from | 102 | - copy-attachments-from |
| 92 | - encrypt | 103 | - encrypt |
| 104 | + - global | ||
| 93 | - overlay | 105 | - overlay |
| 94 | - pages | 106 | - pages |
| 95 | - underlay | 107 | - underlay |
| @@ -112,6 +124,7 @@ options: | @@ -112,6 +124,7 @@ options: | ||
| 112 | - filtered-stream-data | 124 | - filtered-stream-data |
| 113 | - flatten-rotation | 125 | - flatten-rotation |
| 114 | - generate-appearances | 126 | - generate-appearances |
| 127 | + - global | ||
| 115 | - ignore-xref-streams | 128 | - ignore-xref-streams |
| 116 | - is-encrypted | 129 | - is-encrypted |
| 117 | - json-input | 130 | - json-input |
| @@ -399,6 +412,13 @@ json: | @@ -399,6 +412,13 @@ json: | ||
| 399 | - null | 412 | - null |
| 400 | json-stream-data: | 413 | json-stream-data: |
| 401 | json-stream-prefix: | 414 | json-stream-prefix: |
| 415 | + # global options | ||
| 416 | + global: | ||
| 417 | + no-default-limits: | ||
| 418 | + parser-max-container-size: | ||
| 419 | + parser-max-container-size-damaged: | ||
| 420 | + parser-max-errors: | ||
| 421 | + parser-max-nesting: | ||
| 402 | # other options | 422 | # other options |
| 403 | update-from-json: | 423 | update-from-json: |
| 404 | allow-weak-crypto: | 424 | allow-weak-crypto: |
libqpdf/QPDFJob_argv.cc
| @@ -31,6 +31,7 @@ namespace | @@ -31,6 +31,7 @@ namespace | ||
| 31 | std::shared_ptr<QPDFJob::Config> c_main; | 31 | std::shared_ptr<QPDFJob::Config> c_main; |
| 32 | std::shared_ptr<QPDFJob::CopyAttConfig> c_copy_att; | 32 | std::shared_ptr<QPDFJob::CopyAttConfig> c_copy_att; |
| 33 | std::shared_ptr<QPDFJob::AttConfig> c_att; | 33 | std::shared_ptr<QPDFJob::AttConfig> c_att; |
| 34 | + std::shared_ptr<QPDFJob::GlobalConfig> c_global; | ||
| 34 | std::shared_ptr<QPDFJob::PagesConfig> c_pages; | 35 | std::shared_ptr<QPDFJob::PagesConfig> c_pages; |
| 35 | std::shared_ptr<QPDFJob::UOConfig> c_uo; | 36 | std::shared_ptr<QPDFJob::UOConfig> c_uo; |
| 36 | std::shared_ptr<QPDFJob::EncConfig> c_enc; | 37 | std::shared_ptr<QPDFJob::EncConfig> c_enc; |
| @@ -418,6 +419,21 @@ ArgParser::argEndSetPageLabels() | @@ -418,6 +419,21 @@ ArgParser::argEndSetPageLabels() | ||
| 418 | } | 419 | } |
| 419 | 420 | ||
| 420 | void | 421 | void |
| 422 | +ArgParser::argGlobal() | ||
| 423 | +{ | ||
| 424 | + accumulated_args.clear(); | ||
| 425 | + c_global = c_main->global(); | ||
| 426 | + ap.selectOptionTable(O_GLOBAL); | ||
| 427 | +} | ||
| 428 | + | ||
| 429 | +void | ||
| 430 | +ArgParser::argEndGlobal() | ||
| 431 | +{ | ||
| 432 | + c_global->endGlobal(); | ||
| 433 | + c_global = nullptr; | ||
| 434 | +} | ||
| 435 | + | ||
| 436 | +void | ||
| 421 | ArgParser::argJobJsonHelp() | 437 | ArgParser::argJobJsonHelp() |
| 422 | { | 438 | { |
| 423 | *QPDFLogger::defaultLogger()->getInfo() | 439 | *QPDFLogger::defaultLogger()->getInfo() |
libqpdf/QPDFJob_config.cc
| @@ -4,31 +4,53 @@ | @@ -4,31 +4,53 @@ | ||
| 4 | #include <qpdf/QPDFUsage.hh> | 4 | #include <qpdf/QPDFUsage.hh> |
| 5 | #include <qpdf/QTC.hh> | 5 | #include <qpdf/QTC.hh> |
| 6 | #include <qpdf/QUtil.hh> | 6 | #include <qpdf/QUtil.hh> |
| 7 | +#include <qpdf/Util.hh> | ||
| 8 | +#include <qpdf/global_private.hh> | ||
| 7 | 9 | ||
| 8 | #include <concepts> | 10 | #include <concepts> |
| 9 | #include <regex> | 11 | #include <regex> |
| 10 | 12 | ||
| 11 | -static void | ||
| 12 | -int_usage(std::string_view option, std::integral auto min, std::integral auto max) | 13 | +[[noreturn]] static void |
| 14 | +int_usage(std::string_view option, std::integral auto max, std::integral auto min) | ||
| 13 | { | 15 | { |
| 16 | + qpdf_expect(min < max); | ||
| 14 | throw QPDFUsage( | 17 | throw QPDFUsage( |
| 15 | "invalid "s.append(option) + ": must be a number between " + std::to_string(min) + " and " + | 18 | "invalid "s.append(option) + ": must be a number between " + std::to_string(min) + " and " + |
| 16 | std::to_string(max)); | 19 | std::to_string(max)); |
| 17 | } | 20 | } |
| 18 | 21 | ||
| 19 | static int | 22 | static int |
| 20 | -to_int(std::string_view option, std::string const& value, int min, int max) | 23 | +to_int(std::string_view option, std::string const& value, int max, int min) |
| 21 | { | 24 | { |
| 22 | - int result = 0; | 25 | + qpdf_expect(min < max); |
| 23 | try { | 26 | try { |
| 24 | - result = std::stoi(value); | 27 | + int result = std::stoi(value); |
| 25 | if (result < min || result > max) { | 28 | if (result < min || result > max) { |
| 26 | - int_usage(option, min, max); | 29 | + int_usage(option, max, min); |
| 27 | } | 30 | } |
| 31 | + return result; | ||
| 28 | } catch (std::exception&) { | 32 | } catch (std::exception&) { |
| 29 | - int_usage(option, min, max); | 33 | + int_usage(option, max, min); |
| 34 | + } | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +static uint32_t | ||
| 38 | +to_uint32( | ||
| 39 | + std::string_view option, | ||
| 40 | + std::string const& value, | ||
| 41 | + uint32_t max = std::numeric_limits<uint32_t>::max(), | ||
| 42 | + uint32_t min = 0) | ||
| 43 | +{ | ||
| 44 | + qpdf_expect(min < max); | ||
| 45 | + try { | ||
| 46 | + auto result = std::stoll(value); | ||
| 47 | + if (std::cmp_less(result, min) || std::cmp_greater(result, max)) { | ||
| 48 | + int_usage(option, max, min); | ||
| 49 | + } | ||
| 50 | + return static_cast<uint32_t>(result); | ||
| 51 | + } catch (std::exception&) { | ||
| 52 | + int_usage(option, max, min); | ||
| 30 | } | 53 | } |
| 31 | - return result; | ||
| 32 | } | 54 | } |
| 33 | 55 | ||
| 34 | void | 56 | void |
| @@ -156,14 +178,14 @@ QPDFJob::Config::compressStreams(std::string const& parameter) | @@ -156,14 +178,14 @@ QPDFJob::Config::compressStreams(std::string const& parameter) | ||
| 156 | QPDFJob::Config* | 178 | QPDFJob::Config* |
| 157 | QPDFJob::Config::compressionLevel(std::string const& parameter) | 179 | QPDFJob::Config::compressionLevel(std::string const& parameter) |
| 158 | { | 180 | { |
| 159 | - o.m->compression_level = to_int("compression-level", parameter, 1, 9); | 181 | + o.m->compression_level = to_int("compression-level", parameter, 9, 1); |
| 160 | return this; | 182 | return this; |
| 161 | } | 183 | } |
| 162 | 184 | ||
| 163 | QPDFJob::Config* | 185 | QPDFJob::Config* |
| 164 | QPDFJob::Config::jpegQuality(std::string const& parameter) | 186 | QPDFJob::Config::jpegQuality(std::string const& parameter) |
| 165 | { | 187 | { |
| 166 | - o.m->jpeg_quality = to_int("jpeg-quality", parameter, 0, 100); | 188 | + o.m->jpeg_quality = to_int("jpeg-quality", parameter, 100, 0); |
| 167 | return this; | 189 | return this; |
| 168 | } | 190 | } |
| 169 | 191 | ||
| @@ -1140,6 +1162,60 @@ QPDFJob::Config::encrypt( | @@ -1140,6 +1162,60 @@ QPDFJob::Config::encrypt( | ||
| 1140 | return std::shared_ptr<EncConfig>(new EncConfig(this)); | 1162 | return std::shared_ptr<EncConfig>(new EncConfig(this)); |
| 1141 | } | 1163 | } |
| 1142 | 1164 | ||
| 1165 | +QPDFJob::GlobalConfig::GlobalConfig(Config* c) : | ||
| 1166 | + config(c) | ||
| 1167 | +{ | ||
| 1168 | +} | ||
| 1169 | + | ||
| 1170 | +std::shared_ptr<QPDFJob::GlobalConfig> | ||
| 1171 | +QPDFJob::Config::global() | ||
| 1172 | +{ | ||
| 1173 | + return std::make_shared<GlobalConfig>(this); | ||
| 1174 | +} | ||
| 1175 | + | ||
| 1176 | +QPDFJob::Config* | ||
| 1177 | +QPDFJob::GlobalConfig::endGlobal() | ||
| 1178 | +{ | ||
| 1179 | + return config; | ||
| 1180 | +} | ||
| 1181 | + | ||
| 1182 | +QPDFJob::GlobalConfig* | ||
| 1183 | +QPDFJob::GlobalConfig::noDefaultLimits() | ||
| 1184 | +{ | ||
| 1185 | + global::Options::default_limits(false); | ||
| 1186 | + return this; | ||
| 1187 | +} | ||
| 1188 | + | ||
| 1189 | +QPDFJob::GlobalConfig* | ||
| 1190 | +QPDFJob::GlobalConfig::parserMaxContainerSize(const std::string& parameter) | ||
| 1191 | +{ | ||
| 1192 | + global::Limits::parser_max_container_size( | ||
| 1193 | + false, to_uint32("parser-max-container-size", parameter, 4'294'967'295)); | ||
| 1194 | + return this; | ||
| 1195 | +} | ||
| 1196 | + | ||
| 1197 | +QPDFJob::GlobalConfig* | ||
| 1198 | +QPDFJob::GlobalConfig::parserMaxContainerSizeDamaged(const std::string& parameter) | ||
| 1199 | +{ | ||
| 1200 | + global::Limits::parser_max_container_size( | ||
| 1201 | + true, to_uint32("parser-max-container-size-damaged", parameter, 4'294'967'295)); | ||
| 1202 | + return this; | ||
| 1203 | +} | ||
| 1204 | + | ||
| 1205 | +QPDFJob::GlobalConfig* | ||
| 1206 | +QPDFJob::GlobalConfig::parserMaxErrors(const std::string& parameter) | ||
| 1207 | +{ | ||
| 1208 | + global::Limits::parser_max_errors(to_uint32("parser-max-errors", parameter)); | ||
| 1209 | + return this; | ||
| 1210 | +} | ||
| 1211 | + | ||
| 1212 | +QPDFJob::GlobalConfig* | ||
| 1213 | +QPDFJob::GlobalConfig::parserMaxNesting(const std::string& parameter) | ||
| 1214 | +{ | ||
| 1215 | + global::Limits::parser_max_nesting(to_uint32("parser-max-nesting", parameter)); | ||
| 1216 | + return this; | ||
| 1217 | +} | ||
| 1218 | + | ||
| 1143 | QPDFJob::Config* | 1219 | QPDFJob::Config* |
| 1144 | QPDFJob::Config::setPageLabels(const std::vector<std::string>& specs) | 1220 | QPDFJob::Config::setPageLabels(const std::vector<std::string>& specs) |
| 1145 | { | 1221 | { |
libqpdf/QPDFJob_json.cc
| @@ -63,6 +63,7 @@ namespace | @@ -63,6 +63,7 @@ namespace | ||
| 63 | std::shared_ptr<QPDFJob::Config> c_main; | 63 | std::shared_ptr<QPDFJob::Config> c_main; |
| 64 | std::shared_ptr<QPDFJob::CopyAttConfig> c_copy_att; | 64 | std::shared_ptr<QPDFJob::CopyAttConfig> c_copy_att; |
| 65 | std::shared_ptr<QPDFJob::AttConfig> c_att; | 65 | std::shared_ptr<QPDFJob::AttConfig> c_att; |
| 66 | + std::shared_ptr<QPDFJob::GlobalConfig> c_global; | ||
| 66 | std::shared_ptr<QPDFJob::PagesConfig> c_pages; | 67 | std::shared_ptr<QPDFJob::PagesConfig> c_pages; |
| 67 | std::shared_ptr<QPDFJob::UOConfig> c_uo; | 68 | std::shared_ptr<QPDFJob::UOConfig> c_uo; |
| 68 | std::shared_ptr<QPDFJob::EncConfig> c_enc; | 69 | std::shared_ptr<QPDFJob::EncConfig> c_enc; |
| @@ -620,6 +621,19 @@ Handlers::beginSetPageLabelsArray(JSON) | @@ -620,6 +621,19 @@ Handlers::beginSetPageLabelsArray(JSON) | ||
| 620 | } | 621 | } |
| 621 | 622 | ||
| 622 | void | 623 | void |
| 624 | +Handlers::beginGlobal(JSON) | ||
| 625 | +{ | ||
| 626 | + this->c_global = c_main->global(); | ||
| 627 | +} | ||
| 628 | + | ||
| 629 | +void | ||
| 630 | +Handlers::endGlobal() | ||
| 631 | +{ | ||
| 632 | + c_global->endGlobal(); | ||
| 633 | + c_global = nullptr; | ||
| 634 | +} | ||
| 635 | + | ||
| 636 | +void | ||
| 623 | QPDFJob::initializeFromJson(std::string const& json, bool partial) | 637 | QPDFJob::initializeFromJson(std::string const& json, bool partial) |
| 624 | { | 638 | { |
| 625 | std::list<std::string> errors; | 639 | std::list<std::string> errors; |
libqpdf/qpdf/auto_job_decl.hh
| @@ -5,6 +5,7 @@ | @@ -5,6 +5,7 @@ | ||
| 5 | // | 5 | // |
| 6 | // clang-format off | 6 | // clang-format off |
| 7 | // | 7 | // |
| 8 | +static constexpr char const* O_GLOBAL = "global"; | ||
| 8 | static constexpr char const* O_PAGES = "pages"; | 9 | static constexpr char const* O_PAGES = "pages"; |
| 9 | static constexpr char const* O_ENCRYPTION = "encryption"; | 10 | static constexpr char const* O_ENCRYPTION = "encryption"; |
| 10 | static constexpr char const* O_40_BIT_ENCRYPTION = "40-bit encryption"; | 11 | static constexpr char const* O_40_BIT_ENCRYPTION = "40-bit encryption"; |
| @@ -21,11 +22,13 @@ void argShowCrypto(); | @@ -21,11 +22,13 @@ void argShowCrypto(); | ||
| 21 | void argJobJsonHelp(); | 22 | void argJobJsonHelp(); |
| 22 | void argZopfli(); | 23 | void argZopfli(); |
| 23 | void argJsonHelp(std::string const&); | 24 | void argJsonHelp(std::string const&); |
| 25 | +void argEndGlobal(); | ||
| 24 | void argPositional(std::string const&); | 26 | void argPositional(std::string const&); |
| 25 | void argAddAttachment(); | 27 | void argAddAttachment(); |
| 26 | void argCopyAttachmentsFrom(); | 28 | void argCopyAttachmentsFrom(); |
| 27 | void argEmpty(); | 29 | void argEmpty(); |
| 28 | void argEncrypt(); | 30 | void argEncrypt(); |
| 31 | +void argGlobal(); | ||
| 29 | void argOverlay(); | 32 | void argOverlay(); |
| 30 | void argPages(); | 33 | void argPages(); |
| 31 | void argReplaceInput(); | 34 | void argReplaceInput(); |
libqpdf/qpdf/auto_job_help.hh
| @@ -1004,6 +1004,46 @@ Update a PDF file from a JSON file. Please see the "qpdf JSON" | @@ -1004,6 +1004,46 @@ Update a PDF file from a JSON file. Please see the "qpdf JSON" | ||
| 1004 | chapter of the manual for information about how to use this | 1004 | chapter of the manual for information about how to use this |
| 1005 | option. | 1005 | option. |
| 1006 | )"); | 1006 | )"); |
| 1007 | +ap.addHelpTopic("global", "options for changing the behaviour of qpdf", R"(The options below modify the overall behaviour of qpdf. This includes modifying | ||
| 1008 | +implementation limits and changing modes of operation. | ||
| 1009 | +)"); | ||
| 1010 | +ap.addOptionHelp("--global", "global", "begin setting global options and limits", R"(--global [options] -- | ||
| 1011 | + | ||
| 1012 | +Begin setting global options and limits. | ||
| 1013 | +)"); | ||
| 1014 | +ap.addOptionHelp("--no-default-limits", "global", "disable optional default limits", R"(Disables all optional default limits. Explicitly set limits are unaffected. Some | ||
| 1015 | +limits, especially limits designed to prevent stack overflow, cannot be removed | ||
| 1016 | +with this option but can be modified. Where this is the case it is mentioned | ||
| 1017 | +in the entry for the relevant option. | ||
| 1018 | +)"); | ||
| 1019 | +ap.addOptionHelp("--parser-max-nesting", "global", "set the maximum nesting level while parsing objects", R"(--parser-max-nesting=n | ||
| 1020 | + | ||
| 1021 | +Set the maximum nesting level while parsing objects. The maximum nesting level | ||
| 1022 | +is not disabled by --no-default-limits. Defaults to 499. | ||
| 1023 | +)"); | ||
| 1024 | +ap.addOptionHelp("--parser-max-errors", "global", "set the maximum number of errors while parsing", R"(--parser-max-errors=n | ||
| 1025 | + | ||
| 1026 | +Set the maximum number of errors allowed while parsing an indirect object. | ||
| 1027 | +A value of 0 means that no maximum is imposed. Defaults to 15. | ||
| 1028 | +)"); | ||
| 1029 | +ap.addOptionHelp("--parser-max-container-size", "global", "set the maximum container size while parsing", R"(--parser-max-container-size=n | ||
| 1030 | + | ||
| 1031 | +Set the maximum number of top-level objects allowed in a container while | ||
| 1032 | +parsing. The limit applies when the PDF document's xref table is undamaged | ||
| 1033 | +and the object itself can be parsed without errors. The default limit | ||
| 1034 | +is 4,294,967,295. See also --parser-max-container-size-damaged. | ||
| 1035 | +)"); | ||
| 1036 | +ap.addOptionHelp("--parser-max-container-size-damaged", "global", "set the maximum container size while parsing damaged files", R"(--parser-max-container-size-damaged=n | ||
| 1037 | + | ||
| 1038 | +Set the maximum number of top-level objects allowed in a container while | ||
| 1039 | +parsing. The limit applies when the PDF document's xref table is damaged | ||
| 1040 | +or the object itself is damaged. The limit also applies when parsing | ||
| 1041 | +xref streams. The default limit is 5,000. | ||
| 1042 | +See also --parser-max-container-size. | ||
| 1043 | +)"); | ||
| 1044 | +} | ||
| 1045 | +static void add_help_9(QPDFArgParser& ap) | ||
| 1046 | +{ | ||
| 1007 | ap.addHelpTopic("testing", "options for testing or debugging", R"(The options below are useful when writing automated test code that | 1047 | ap.addHelpTopic("testing", "options for testing or debugging", R"(The options below are useful when writing automated test code that |
| 1008 | includes files created by qpdf or when testing qpdf itself. | 1048 | includes files created by qpdf or when testing qpdf itself. |
| 1009 | )"); | 1049 | )"); |
| @@ -1039,6 +1079,7 @@ static void add_help(QPDFArgParser& ap) | @@ -1039,6 +1079,7 @@ static void add_help(QPDFArgParser& ap) | ||
| 1039 | add_help_6(ap); | 1079 | add_help_6(ap); |
| 1040 | add_help_7(ap); | 1080 | add_help_7(ap); |
| 1041 | add_help_8(ap); | 1081 | add_help_8(ap); |
| 1082 | + add_help_9(ap); | ||
| 1042 | ap.addHelpFooter("For detailed help, visit the qpdf manual: https://qpdf.readthedocs.io\n"); | 1083 | ap.addHelpFooter("For detailed help, visit the qpdf manual: https://qpdf.readthedocs.io\n"); |
| 1043 | } | 1084 | } |
| 1044 | 1085 |
libqpdf/qpdf/auto_job_init.hh
| @@ -34,6 +34,12 @@ this->ap.addBare("show-crypto", b(&ArgParser::argShowCrypto)); | @@ -34,6 +34,12 @@ this->ap.addBare("show-crypto", b(&ArgParser::argShowCrypto)); | ||
| 34 | this->ap.addBare("job-json-help", b(&ArgParser::argJobJsonHelp)); | 34 | this->ap.addBare("job-json-help", b(&ArgParser::argJobJsonHelp)); |
| 35 | this->ap.addBare("zopfli", b(&ArgParser::argZopfli)); | 35 | this->ap.addBare("zopfli", b(&ArgParser::argZopfli)); |
| 36 | this->ap.addChoices("json-help", p(&ArgParser::argJsonHelp), false, json_version_choices); | 36 | this->ap.addChoices("json-help", p(&ArgParser::argJsonHelp), false, json_version_choices); |
| 37 | +this->ap.registerOptionTable("global", b(&ArgParser::argEndGlobal)); | ||
| 38 | +this->ap.addBare("no-default-limits", [this](){c_global->noDefaultLimits();}); | ||
| 39 | +this->ap.addRequiredParameter("parser-max-container-size", [this](std::string const& x){c_global->parserMaxContainerSize(x);}, "level"); | ||
| 40 | +this->ap.addRequiredParameter("parser-max-container-size-damaged", [this](std::string const& x){c_global->parserMaxContainerSizeDamaged(x);}, "level"); | ||
| 41 | +this->ap.addRequiredParameter("parser-max-errors", [this](std::string const& x){c_global->parserMaxErrors(x);}, "level"); | ||
| 42 | +this->ap.addRequiredParameter("parser-max-nesting", [this](std::string const& x){c_global->parserMaxNesting(x);}, "level"); | ||
| 37 | this->ap.selectMainOptionTable(); | 43 | this->ap.selectMainOptionTable(); |
| 38 | this->ap.addPositional(p(&ArgParser::argPositional)); | 44 | this->ap.addPositional(p(&ArgParser::argPositional)); |
| 39 | this->ap.addBare("add-attachment", b(&ArgParser::argAddAttachment)); | 45 | this->ap.addBare("add-attachment", b(&ArgParser::argAddAttachment)); |
| @@ -50,6 +56,7 @@ this->ap.addBare("externalize-inline-images", [this](){c_main->externalizeInline | @@ -50,6 +56,7 @@ this->ap.addBare("externalize-inline-images", [this](){c_main->externalizeInline | ||
| 50 | this->ap.addBare("filtered-stream-data", [this](){c_main->filteredStreamData();}); | 56 | this->ap.addBare("filtered-stream-data", [this](){c_main->filteredStreamData();}); |
| 51 | this->ap.addBare("flatten-rotation", [this](){c_main->flattenRotation();}); | 57 | this->ap.addBare("flatten-rotation", [this](){c_main->flattenRotation();}); |
| 52 | this->ap.addBare("generate-appearances", [this](){c_main->generateAppearances();}); | 58 | this->ap.addBare("generate-appearances", [this](){c_main->generateAppearances();}); |
| 59 | +this->ap.addBare("global", b(&ArgParser::argGlobal)); | ||
| 53 | this->ap.addBare("ignore-xref-streams", [this](){c_main->ignoreXrefStreams();}); | 60 | this->ap.addBare("ignore-xref-streams", [this](){c_main->ignoreXrefStreams();}); |
| 54 | this->ap.addBare("is-encrypted", [this](){c_main->isEncrypted();}); | 61 | this->ap.addBare("is-encrypted", [this](){c_main->isEncrypted();}); |
| 55 | this->ap.addBare("json-input", [this](){c_main->jsonInput();}); | 62 | this->ap.addBare("json-input", [this](){c_main->jsonInput();}); |
libqpdf/qpdf/auto_job_json_decl.hh
| @@ -24,6 +24,8 @@ void beginJsonKeyArray(JSON); | @@ -24,6 +24,8 @@ void beginJsonKeyArray(JSON); | ||
| 24 | void endJsonKeyArray(); | 24 | void endJsonKeyArray(); |
| 25 | void beginJsonObjectArray(JSON); | 25 | void beginJsonObjectArray(JSON); |
| 26 | void endJsonObjectArray(); | 26 | void endJsonObjectArray(); |
| 27 | +void beginGlobal(JSON); | ||
| 28 | +void endGlobal(); | ||
| 27 | void beginAddAttachmentArray(JSON); | 29 | void beginAddAttachmentArray(JSON); |
| 28 | void endAddAttachmentArray(); | 30 | void endAddAttachmentArray(); |
| 29 | void beginAddAttachment(JSON); | 31 | void beginAddAttachment(JSON); |
libqpdf/qpdf/auto_job_json_init.hh
| @@ -272,6 +272,24 @@ popHandler(); // key: jsonStreamData | @@ -272,6 +272,24 @@ popHandler(); // key: jsonStreamData | ||
| 272 | pushKey("jsonStreamPrefix"); | 272 | pushKey("jsonStreamPrefix"); |
| 273 | addParameter([this](std::string const& p) { c_main->jsonStreamPrefix(p); }); | 273 | addParameter([this](std::string const& p) { c_main->jsonStreamPrefix(p); }); |
| 274 | popHandler(); // key: jsonStreamPrefix | 274 | popHandler(); // key: jsonStreamPrefix |
| 275 | +pushKey("global"); | ||
| 276 | +beginDict(bindJSON(&Handlers::beginGlobal), bindBare(&Handlers::endGlobal)); // .global | ||
| 277 | +pushKey("noDefaultLimits"); | ||
| 278 | +addBare([this]() { c_global->noDefaultLimits(); }); | ||
| 279 | +popHandler(); // key: noDefaultLimits | ||
| 280 | +pushKey("parserMaxContainerSize"); | ||
| 281 | +addParameter([this](std::string const& p) { c_global->parserMaxContainerSize(p); }); | ||
| 282 | +popHandler(); // key: parserMaxContainerSize | ||
| 283 | +pushKey("parserMaxContainerSizeDamaged"); | ||
| 284 | +addParameter([this](std::string const& p) { c_global->parserMaxContainerSizeDamaged(p); }); | ||
| 285 | +popHandler(); // key: parserMaxContainerSizeDamaged | ||
| 286 | +pushKey("parserMaxErrors"); | ||
| 287 | +addParameter([this](std::string const& p) { c_global->parserMaxErrors(p); }); | ||
| 288 | +popHandler(); // key: parserMaxErrors | ||
| 289 | +pushKey("parserMaxNesting"); | ||
| 290 | +addParameter([this](std::string const& p) { c_global->parserMaxNesting(p); }); | ||
| 291 | +popHandler(); // key: parserMaxNesting | ||
| 292 | +popHandler(); // key: global | ||
| 275 | pushKey("updateFromJson"); | 293 | pushKey("updateFromJson"); |
| 276 | addParameter([this](std::string const& p) { c_main->updateFromJson(p); }); | 294 | addParameter([this](std::string const& p) { c_main->updateFromJson(p); }); |
| 277 | popHandler(); // key: updateFromJson | 295 | popHandler(); // key: updateFromJson |
libqpdf/qpdf/auto_job_schema.hh
| @@ -90,6 +90,13 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({ | @@ -90,6 +90,13 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({ | ||
| 90 | ], | 90 | ], |
| 91 | "jsonStreamData": "how to handle streams in json output", | 91 | "jsonStreamData": "how to handle streams in json output", |
| 92 | "jsonStreamPrefix": "prefix for json stream data files", | 92 | "jsonStreamPrefix": "prefix for json stream data files", |
| 93 | + "global": { | ||
| 94 | + "noDefaultLimits": "disable optional default limits", | ||
| 95 | + "parserMaxContainerSize": "set the maximum container size while parsing", | ||
| 96 | + "parserMaxContainerSizeDamaged": "set the maximum container size while parsing damaged files", | ||
| 97 | + "parserMaxErrors": "set the maximum number of errors while parsing", | ||
| 98 | + "parserMaxNesting": "set the maximum nesting level while parsing objects" | ||
| 99 | + }, | ||
| 93 | "updateFromJson": "update a PDF from qpdf JSON", | 100 | "updateFromJson": "update a PDF from qpdf JSON", |
| 94 | "allowWeakCrypto": "allow insecure cryptographic algorithms", | 101 | "allowWeakCrypto": "allow insecure cryptographic algorithms", |
| 95 | "keepFilesOpen": "manage keeping multiple files open", | 102 | "keepFilesOpen": "manage keeping multiple files open", |
libtests/objects.cc
| @@ -5,6 +5,7 @@ | @@ -5,6 +5,7 @@ | ||
| 5 | #include <qpdf/QPDF.hh> | 5 | #include <qpdf/QPDF.hh> |
| 6 | 6 | ||
| 7 | #include <qpdf/QIntC.hh> | 7 | #include <qpdf/QIntC.hh> |
| 8 | +#include <qpdf/QPDFJob.hh> | ||
| 8 | #include <qpdf/QPDFObjectHandle_private.hh> | 9 | #include <qpdf/QPDFObjectHandle_private.hh> |
| 9 | #include <qpdf/QUtil.hh> | 10 | #include <qpdf/QUtil.hh> |
| 10 | #include <qpdf/global.hh> | 11 | #include <qpdf/global.hh> |
| @@ -237,6 +238,47 @@ test_2(QPDF& pdf, char const* arg2) | @@ -237,6 +238,47 @@ test_2(QPDF& pdf, char const* arg2) | ||
| 237 | } catch (std::exception&) { | 238 | } catch (std::exception&) { |
| 238 | } | 239 | } |
| 239 | assert(qpdf::global::limit_errors() == 2); | 240 | assert(qpdf::global::limit_errors() == 2); |
| 241 | + | ||
| 242 | + // Test global settings using the QPDFJob interface | ||
| 243 | + QPDFJob j; | ||
| 244 | + j.config() | ||
| 245 | + ->inputFile("minimal.pdf") | ||
| 246 | + ->global() | ||
| 247 | + ->parserMaxNesting("111") | ||
| 248 | + ->parserMaxErrors("112") | ||
| 249 | + ->parserMaxContainerSize("113") | ||
| 250 | + ->parserMaxContainerSizeDamaged("114") | ||
| 251 | + ->noDefaultLimits() | ||
| 252 | + ->endGlobal() | ||
| 253 | + ->outputFile("a.pdf"); | ||
| 254 | + auto qpdf = j.createQPDF(); | ||
| 255 | + assert(parser_max_nesting() == 111); | ||
| 256 | + assert(parser_max_errors() == 112); | ||
| 257 | + assert(parser_max_container_size() == 113); | ||
| 258 | + assert(parser_max_container_size_damaged() == 114); | ||
| 259 | + assert(!default_limits()); | ||
| 260 | + | ||
| 261 | + // Test global settings using the JobJSON | ||
| 262 | + QPDFJob jj; | ||
| 263 | + jj.initializeFromJson(R"( | ||
| 264 | + { | ||
| 265 | + "inputFile": "minimal.pdf", | ||
| 266 | + "global": { | ||
| 267 | + "parserMaxNesting": "211", | ||
| 268 | + "parserMaxErrors": "212", | ||
| 269 | + "parserMaxContainerSize": "213", | ||
| 270 | + "parserMaxContainerSizeDamaged": "214", | ||
| 271 | + "noDefaultLimits": "" | ||
| 272 | + }, | ||
| 273 | + "outputFile": "a.pdf" | ||
| 274 | + } | ||
| 275 | + )"); | ||
| 276 | + qpdf = j.createQPDF(); | ||
| 277 | + assert(parser_max_nesting() == 211); | ||
| 278 | + assert(parser_max_errors() == 212); | ||
| 279 | + assert(parser_max_container_size() == 213); | ||
| 280 | + assert(parser_max_container_size_damaged() == 214); | ||
| 281 | + assert(!default_limits()); | ||
| 240 | } | 282 | } |
| 241 | 283 | ||
| 242 | void | 284 | void |
manual/cli.rst
| @@ -3762,6 +3762,110 @@ Related Options | @@ -3762,6 +3762,110 @@ Related Options | ||
| 3762 | For a information about how to use this option, please see | 3762 | For a information about how to use this option, please see |
| 3763 | :ref:`json`. | 3763 | :ref:`json`. |
| 3764 | 3764 | ||
| 3765 | +.. _global-options: | ||
| 3766 | + | ||
| 3767 | +Global Options | ||
| 3768 | +-------------- | ||
| 3769 | + | ||
| 3770 | +.. help-topic global: options for changing the behaviour of qpdf | ||
| 3771 | + | ||
| 3772 | + The options below modify the overall behaviour of qpdf. This includes modifying | ||
| 3773 | + implementation limits and changing modes of operation. | ||
| 3774 | + | ||
| 3775 | +The options below modify the overall behaviour of qpdf. This includes modifying implementation | ||
| 3776 | +limits and changing modes of operation. | ||
| 3777 | + | ||
| 3778 | +Related Options | ||
| 3779 | +~~~~~~~~~~~~~~~ | ||
| 3780 | + | ||
| 3781 | +.. qpdf:option:: --global [options] -- | ||
| 3782 | + | ||
| 3783 | + .. help: begin setting global options and limits | ||
| 3784 | + | ||
| 3785 | + Begin setting global options and limits. | ||
| 3786 | + | ||
| 3787 | +Begin setting global options and limits. | ||
| 3788 | + | ||
| 3789 | + | ||
| 3790 | +Global Limits | ||
| 3791 | +~~~~~~~~~~~~~ | ||
| 3792 | + | ||
| 3793 | +qpdf uses a number of global limits to protect itself from damaged and specially constructed PDF | ||
| 3794 | +files. Without these limits such files can cause qpdf to crash and/or to consume excessive | ||
| 3795 | +processor and memory resources. Very few legitimate PDF files exceed these limits, however | ||
| 3796 | +where necessary the limits can be modified or entirely removed by the following options. | ||
| 3797 | + | ||
| 3798 | +.. qpdf:option:: --no-default-limits | ||
| 3799 | + | ||
| 3800 | + .. help: disable optional default limits | ||
| 3801 | + | ||
| 3802 | + Disables all optional default limits. Explicitly set limits are unaffected. Some | ||
| 3803 | + limits, especially limits designed to prevent stack overflow, cannot be removed | ||
| 3804 | + with this option but can be modified. Where this is the case it is mentioned | ||
| 3805 | + in the entry for the relevant option. | ||
| 3806 | + | ||
| 3807 | +Disables all optional default limits. Explicitly set limits are unaffected. Some limits, | ||
| 3808 | +especially limits designed to prevent stack overflow, cannot be removed with this option | ||
| 3809 | +but can be modified. Where this is the case it is mentioned in the entry for the relevant | ||
| 3810 | +option. | ||
| 3811 | + | ||
| 3812 | +Parser Limits | ||
| 3813 | +............. | ||
| 3814 | + | ||
| 3815 | +.. qpdf:option:: --parser-max-nesting=n | ||
| 3816 | + | ||
| 3817 | + .. help: set the maximum nesting level while parsing objects | ||
| 3818 | + | ||
| 3819 | + Set the maximum nesting level while parsing objects. The maximum nesting level | ||
| 3820 | + is not disabled by --no-default-limits. Defaults to 499. | ||
| 3821 | + | ||
| 3822 | +Set the maximum nesting level while parsing objects. The maximum nesting level is not | ||
| 3823 | +disabled by :qpdf:ref:`--no-default-limits`. Defaults to 499. | ||
| 3824 | + | ||
| 3825 | + | ||
| 3826 | +.. qpdf:option:: --parser-max-errors=n | ||
| 3827 | + | ||
| 3828 | + .. help: set the maximum number of errors while parsing | ||
| 3829 | + | ||
| 3830 | + Set the maximum number of errors allowed while parsing an indirect object. | ||
| 3831 | + A value of 0 means that no maximum is imposed. Defaults to 15. | ||
| 3832 | + | ||
| 3833 | +Set the maximum number of errors allowed while parsing an indirect object. | ||
| 3834 | +A value of 0 means that no maximum is imposed. Defaults to 15. | ||
| 3835 | + | ||
| 3836 | +.. qpdf:option:: --parser-max-container-size=n | ||
| 3837 | + | ||
| 3838 | + .. help: set the maximum container size while parsing | ||
| 3839 | + | ||
| 3840 | + Set the maximum number of top-level objects allowed in a container while | ||
| 3841 | + parsing. The limit applies when the PDF document's xref table is undamaged | ||
| 3842 | + and the object itself can be parsed without errors. The default limit | ||
| 3843 | + is 4,294,967,295. See also --parser-max-container-size-damaged. | ||
| 3844 | + | ||
| 3845 | + | ||
| 3846 | +Set the maximum number of top-level objects allowed in a container while | ||
| 3847 | +parsing. The limit applies when the PDF document's xref table is undamaged | ||
| 3848 | +and the object itself can be parsed without errors. The default limit | ||
| 3849 | +is 4,294,967,295. See also :qpdf:ref:`--parser-max-container-size-damaged`. | ||
| 3850 | + | ||
| 3851 | + | ||
| 3852 | +.. qpdf:option:: --parser-max-container-size-damaged=n | ||
| 3853 | + | ||
| 3854 | + .. help: set the maximum container size while parsing damaged files | ||
| 3855 | + | ||
| 3856 | + Set the maximum number of top-level objects allowed in a container while | ||
| 3857 | + parsing. The limit applies when the PDF document's xref table is damaged | ||
| 3858 | + or the object itself is damaged. The limit also applies when parsing | ||
| 3859 | + xref streams. The default limit is 5,000. | ||
| 3860 | + See also --parser-max-container-size. | ||
| 3861 | + | ||
| 3862 | + | ||
| 3863 | +Set the maximum number of top-level objects allowed in a container while | ||
| 3864 | +parsing. The limit applies when the PDF document's xref table is damaged | ||
| 3865 | +or the object itself is damaged. The limit also applies when parsing | ||
| 3866 | +xref streams. The default limit is 5,000. | ||
| 3867 | +See also :qpdf:ref:`--parser-max-container-size`. | ||
| 3868 | + | ||
| 3765 | .. _test-options: | 3869 | .. _test-options: |
| 3766 | 3870 | ||
| 3767 | Options for Testing or Debugging | 3871 | Options for Testing or Debugging |
manual/qpdf.1
| @@ -1191,6 +1191,51 @@ how to use this option. | @@ -1191,6 +1191,51 @@ how to use this option. | ||
| 1191 | Update a PDF file from a JSON file. Please see the "qpdf JSON" | 1191 | Update a PDF file from a JSON file. Please see the "qpdf JSON" |
| 1192 | chapter of the manual for information about how to use this | 1192 | chapter of the manual for information about how to use this |
| 1193 | option. | 1193 | option. |
| 1194 | +.SH GLOBAL (options for changing the behaviour of qpdf) | ||
| 1195 | +The options below modify the overall behaviour of qpdf. This includes modifying | ||
| 1196 | +implementation limits and changing modes of operation. | ||
| 1197 | +.PP | ||
| 1198 | +Related Options: | ||
| 1199 | +.TP | ||
| 1200 | +.B --global \-\- begin setting global options and limits | ||
| 1201 | +--global [options] -- | ||
| 1202 | + | ||
| 1203 | +Begin setting global options and limits. | ||
| 1204 | +.TP | ||
| 1205 | +.B --no-default-limits \-\- disable optional default limits | ||
| 1206 | +Disables all optional default limits. Explicitly set limits are unaffected. Some | ||
| 1207 | +limits, especially limits designed to prevent stack overflow, cannot be removed | ||
| 1208 | +with this option but can be modified. Where this is the case it is mentioned | ||
| 1209 | +in the entry for the relevant option. | ||
| 1210 | +.TP | ||
| 1211 | +.B --parser-max-nesting \-\- set the maximum nesting level while parsing objects | ||
| 1212 | +--parser-max-nesting=n | ||
| 1213 | + | ||
| 1214 | +Set the maximum nesting level while parsing objects. The maximum nesting level | ||
| 1215 | +is not disabled by --no-default-limits. Defaults to 499. | ||
| 1216 | +.TP | ||
| 1217 | +.B --parser-max-errors \-\- set the maximum number of errors while parsing | ||
| 1218 | +--parser-max-errors=n | ||
| 1219 | + | ||
| 1220 | +Set the maximum number of errors allowed while parsing an indirect object. | ||
| 1221 | +A value of 0 means that no maximum is imposed. Defaults to 15. | ||
| 1222 | +.TP | ||
| 1223 | +.B --parser-max-container-size \-\- set the maximum container size while parsing | ||
| 1224 | +--parser-max-container-size=n | ||
| 1225 | + | ||
| 1226 | +Set the maximum number of top-level objects allowed in a container while | ||
| 1227 | +parsing. The limit applies when the PDF document's xref table is undamaged | ||
| 1228 | +and the object itself can be parsed without errors. The default limit | ||
| 1229 | +is 4,294,967,295. See also --parser-max-container-size-damaged. | ||
| 1230 | +.TP | ||
| 1231 | +.B --parser-max-container-size-damaged \-\- set the maximum container size while parsing damaged files | ||
| 1232 | +--parser-max-container-size-damaged=n | ||
| 1233 | + | ||
| 1234 | +Set the maximum number of top-level objects allowed in a container while | ||
| 1235 | +parsing. The limit applies when the PDF document's xref table is damaged | ||
| 1236 | +or the object itself is damaged. The limit also applies when parsing | ||
| 1237 | +xref streams. The default limit is 5,000. | ||
| 1238 | +See also --parser-max-container-size. | ||
| 1194 | .SH TESTING (options for testing or debugging) | 1239 | .SH TESTING (options for testing or debugging) |
| 1195 | The options below are useful when writing automated test code that | 1240 | The options below are useful when writing automated test code that |
| 1196 | includes files created by qpdf or when testing qpdf itself. | 1241 | includes files created by qpdf or when testing qpdf itself. |
qpdf/qtest/arg-parsing.test
| @@ -15,7 +15,7 @@ cleanup(); | @@ -15,7 +15,7 @@ cleanup(); | ||
| 15 | 15 | ||
| 16 | my $td = new TestDriver('arg-parsing'); | 16 | my $td = new TestDriver('arg-parsing'); |
| 17 | 17 | ||
| 18 | -my $n_tests = 32; | 18 | +my $n_tests = 33; |
| 19 | 19 | ||
| 20 | $td->runtest("required argument", | 20 | $td->runtest("required argument", |
| 21 | {$td->COMMAND => "qpdf --password minimal.pdf"}, | 21 | {$td->COMMAND => "qpdf --password minimal.pdf"}, |
| @@ -187,5 +187,12 @@ $td->runtest("bad jpeg-quality", | @@ -187,5 +187,12 @@ $td->runtest("bad jpeg-quality", | ||
| 187 | $td->EXIT_STATUS => 2}, | 187 | $td->EXIT_STATUS => 2}, |
| 188 | $td->NORMALIZE_NEWLINES); | 188 | $td->NORMALIZE_NEWLINES); |
| 189 | 189 | ||
| 190 | +$td->runtest("bad objects-container-max-container-size", | ||
| 191 | + {$td->COMMAND => "qpdf --global --parser-max-container-size=-1 -- minimal.pdf"}, | ||
| 192 | + {$td->REGEXP => | ||
| 193 | + "invalid parser-max-container-size: must be a number between 0 and 4294967295", | ||
| 194 | + $td->EXIT_STATUS => 2}, | ||
| 195 | + $td->NORMALIZE_NEWLINES); | ||
| 196 | + | ||
| 190 | cleanup(); | 197 | cleanup(); |
| 191 | $td->report($n_tests); | 198 | $td->report($n_tests); |
qpdf/qtest/global.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | ||
| 2 | +require 5.008; | ||
| 3 | +use warnings; | ||
| 4 | +use strict; | ||
| 5 | +use File::Copy; | ||
| 6 | + | ||
| 7 | +unshift(@INC, '.'); | ||
| 8 | +require qpdf_test_helpers; | ||
| 9 | + | ||
| 10 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | ||
| 11 | + | ||
| 12 | +require TestDriver; | ||
| 13 | + | ||
| 14 | +cleanup(); | ||
| 15 | + | ||
| 16 | +my $td = new TestDriver('global'); | ||
| 17 | + | ||
| 18 | +my $n_tests = 4; | ||
| 19 | + | ||
| 20 | +$td->runtest("parser-max-nesting", | ||
| 21 | + {$td->COMMAND => "qpdf --global --parser-max-nesting=4 -- global.pdf a.pdf"}, | ||
| 22 | + {$td->FILE => "global1.out", | ||
| 23 | + $td->EXIT_STATUS => 3}, | ||
| 24 | + $td->NORMALIZE_NEWLINES); | ||
| 25 | + | ||
| 26 | +$td->runtest("parser-max-errors", | ||
| 27 | + {$td->COMMAND => "qpdf --global --parser-max-errors=2 -- global_damaged.pdf a.pdf"}, | ||
| 28 | + {$td->FILE => "global2.out", | ||
| 29 | + $td->EXIT_STATUS => 3}, | ||
| 30 | + $td->NORMALIZE_NEWLINES); | ||
| 31 | + | ||
| 32 | +$td->runtest("parser-max-container-size", | ||
| 33 | + {$td->COMMAND => "qpdf --global --parser-max-container-size=3 -- global.pdf a.pdf"}, | ||
| 34 | + {$td->FILE => "global3.out", | ||
| 35 | + $td->EXIT_STATUS => 3}, | ||
| 36 | + $td->NORMALIZE_NEWLINES); | ||
| 37 | + | ||
| 38 | +$td->runtest("parser-max-container-size-damaged", | ||
| 39 | + {$td->COMMAND => "qpdf --global --parser-max-container-size-damaged=9 -- global_damaged.pdf a.pdf"}, | ||
| 40 | + {$td->FILE => "global4.out", | ||
| 41 | + $td->EXIT_STATUS => 3}, | ||
| 42 | + $td->NORMALIZE_NEWLINES); | ||
| 43 | + | ||
| 44 | +cleanup(); | ||
| 45 | +$td->report($n_tests); |
qpdf/qtest/qpdf/global.pdf
0 โ 100644
| 1 | +%PDF-1.3 | ||
| 2 | +1 0 obj | ||
| 3 | +<< | ||
| 4 | + /Type /Catalog | ||
| 5 | + /Pages 2 0 R | ||
| 6 | +>> | ||
| 7 | +endobj | ||
| 8 | + | ||
| 9 | +2 0 obj | ||
| 10 | +<< | ||
| 11 | + /Type /Pages | ||
| 12 | + /Kids [ | ||
| 13 | + 3 0 R | ||
| 14 | + ] | ||
| 15 | + /Count 1 | ||
| 16 | +>> | ||
| 17 | +endobj | ||
| 18 | + | ||
| 19 | +3 0 obj | ||
| 20 | +<< | ||
| 21 | + /Type /Page | ||
| 22 | + /Parent 2 0 R | ||
| 23 | + /MediaBox [0 0 612 792] | ||
| 24 | + /Contents 4 0 R | ||
| 25 | + /Resources << | ||
| 26 | + /ProcSet 5 0 R | ||
| 27 | + /Font << | ||
| 28 | + /F1 6 0 R | ||
| 29 | + >> | ||
| 30 | + >> | ||
| 31 | +>> | ||
| 32 | +endobj | ||
| 33 | + | ||
| 34 | +4 0 obj | ||
| 35 | +<< | ||
| 36 | + /Length 44 | ||
| 37 | +>> | ||
| 38 | +stream | ||
| 39 | +BT | ||
| 40 | + /F1 24 Tf | ||
| 41 | + 72 720 Td | ||
| 42 | + (Potato) Tj | ||
| 43 | +ET | ||
| 44 | +endstream | ||
| 45 | +endobj | ||
| 46 | + | ||
| 47 | +5 0 obj | ||
| 48 | +[ | ||
| 49 | |||
| 50 | + /Text | ||
| 51 | +] | ||
| 52 | +endobj | ||
| 53 | + | ||
| 54 | +6 0 obj | ||
| 55 | +<< | ||
| 56 | + /Type /Font | ||
| 57 | + /Subtype /Type1 | ||
| 58 | + /Name /F1 | ||
| 59 | + /BaseFont /Helvetica | ||
| 60 | + /Encoding /WinAnsiEncoding | ||
| 61 | +>> | ||
| 62 | +endobj | ||
| 63 | + | ||
| 64 | +xref | ||
| 65 | +0 7 | ||
| 66 | +0000000000 65535 f | ||
| 67 | +0000000009 00000 n | ||
| 68 | +0000000063 00000 n | ||
| 69 | +0000000135 00000 n | ||
| 70 | +0000000307 00000 n | ||
| 71 | +0000000403 00000 n | ||
| 72 | +0000000438 00000 n | ||
| 73 | +trailer << | ||
| 74 | + /Size 7 | ||
| 75 | + /Root 1 0 R | ||
| 76 | + /Nesting [ [ [ [ [ /1 /2 /3 /4 /5 /6 /7 /8 /9 /10 ] ] ] ] ] | ||
| 77 | +>> | ||
| 78 | +startxref | ||
| 79 | +556 | ||
| 80 | +%%EOF |
qpdf/qtest/qpdf/global1.out
0 โ 100644
| 1 | +WARNING: global.pdf (trailer, offset 759): limits error(parser-max-nesting): ignoring excessively deeply nested data structure | ||
| 2 | +WARNING: global.pdf: file is damaged | ||
| 3 | +WARNING: global.pdf (offset 712): expected trailer dictionary | ||
| 4 | +WARNING: global.pdf: Attempting to reconstruct cross-reference table | ||
| 5 | +WARNING: global.pdf (trailer, offset 759): limits error(parser-max-nesting): ignoring excessively deeply nested data structure | ||
| 6 | +WARNING: global.pdf: unable to find trailer dictionary while recovering damaged file | ||
| 7 | +qpdf: operation succeeded with warnings; resulting file may have some problems |
qpdf/qtest/qpdf/global2.out
0 โ 100644
| 1 | +WARNING: global_damaged.pdf: file is damaged | ||
| 2 | +WARNING: global_damaged.pdf (offset 55): xref not found | ||
| 3 | +WARNING: global_damaged.pdf: Attempting to reconstruct cross-reference table | ||
| 4 | +WARNING: global_damaged.pdf (trailer, offset 764): unknown token while reading object; treating as null | ||
| 5 | +WARNING: global_damaged.pdf (trailer, offset 767): unknown token while reading object; treating as null | ||
| 6 | +WARNING: global_damaged.pdf (trailer, offset 767): limits error(parser-max-errors): too many errors during parsing; treating object as null | ||
| 7 | +WARNING: global_damaged.pdf: unable to find trailer dictionary while recovering damaged file | ||
| 8 | +qpdf: operation succeeded with warnings; resulting file may have some problems |
qpdf/qtest/qpdf/global3.out
0 โ 100644
| 1 | +WARNING: global.pdf (trailer, offset 770): limits error(parser-max-container-size): encountered an array or dictionary with more than 3 elements during xref recovery; giving up on reading object | ||
| 2 | +WARNING: global.pdf: file is damaged | ||
| 3 | +WARNING: global.pdf (offset 712): expected trailer dictionary | ||
| 4 | +WARNING: global.pdf: Attempting to reconstruct cross-reference table | ||
| 5 | +qpdf: operation succeeded with warnings; resulting file may have some problems |
qpdf/qtest/qpdf/global4.out
0 โ 100644
| 1 | +WARNING: global_damaged.pdf: file is damaged | ||
| 2 | +WARNING: global_damaged.pdf (offset 55): xref not found | ||
| 3 | +WARNING: global_damaged.pdf: Attempting to reconstruct cross-reference table | ||
| 4 | +WARNING: global_damaged.pdf (trailer, offset 764): unknown token while reading object; treating as null | ||
| 5 | +WARNING: global_damaged.pdf (trailer, offset 767): unknown token while reading object; treating as null | ||
| 6 | +WARNING: global_damaged.pdf (trailer, offset 770): unknown token while reading object; treating as null | ||
| 7 | +WARNING: global_damaged.pdf (trailer, offset 788): limits error(parser-max-container-size-damaged): encountered errors while parsing an array or dictionary with more than 9 elements; giving up on reading object | ||
| 8 | +WARNING: global_damaged.pdf: unable to find trailer dictionary while recovering damaged file | ||
| 9 | +qpdf: operation succeeded with warnings; resulting file may have some problems |
qpdf/qtest/qpdf/global_damaged.pdf
0 โ 100644
| 1 | +%PDF-1.3 | ||
| 2 | +1 0 obj | ||
| 3 | +<< | ||
| 4 | + /Type /Catalog | ||
| 5 | + /Pages 2 0 R | ||
| 6 | +>> | ||
| 7 | +endobj | ||
| 8 | + | ||
| 9 | +2 0 obj | ||
| 10 | +<< | ||
| 11 | + /Type /Pages | ||
| 12 | + /Kids [ | ||
| 13 | + 3 0 R | ||
| 14 | + ] | ||
| 15 | + /Count 1 | ||
| 16 | +>> | ||
| 17 | +endobj | ||
| 18 | + | ||
| 19 | +3 0 obj | ||
| 20 | +<< | ||
| 21 | + /Type /Page | ||
| 22 | + /Parent 2 0 R | ||
| 23 | + /MediaBox [0 0 612 792] | ||
| 24 | + /Contents 4 0 R | ||
| 25 | + /Resources << | ||
| 26 | + /ProcSet 5 0 R | ||
| 27 | + /Font << | ||
| 28 | + /F1 6 0 R | ||
| 29 | + >> | ||
| 30 | + >> | ||
| 31 | +>> | ||
| 32 | +endobj | ||
| 33 | + | ||
| 34 | +4 0 obj | ||
| 35 | +<< | ||
| 36 | + /Length 44 | ||
| 37 | +>> | ||
| 38 | +stream | ||
| 39 | +BT | ||
| 40 | + /F1 24 Tf | ||
| 41 | + 72 720 Td | ||
| 42 | + (Potato) Tj | ||
| 43 | +ET | ||
| 44 | +endstream | ||
| 45 | +endobj | ||
| 46 | + | ||
| 47 | +5 0 obj | ||
| 48 | +[ | ||
| 49 | |||
| 50 | + /Text | ||
| 51 | +] | ||
| 52 | +endobj | ||
| 53 | + | ||
| 54 | +6 0 obj | ||
| 55 | +<< | ||
| 56 | + /Type /Font | ||
| 57 | + /Subtype /Type1 | ||
| 58 | + /Name /F1 | ||
| 59 | + /BaseFont /Helvetica | ||
| 60 | + /Encoding /WinAnsiEncoding | ||
| 61 | +>> | ||
| 62 | +endobj | ||
| 63 | + | ||
| 64 | +xref | ||
| 65 | +0 7 | ||
| 66 | +0000000000 65535 f | ||
| 67 | +0000000009 00000 n | ||
| 68 | +0000000063 00000 n | ||
| 69 | +0000000135 00000 n | ||
| 70 | +0000000307 00000 n | ||
| 71 | +0000000403 00000 n | ||
| 72 | +0000000438 00000 n | ||
| 73 | +trailer << | ||
| 74 | + /Size 7 | ||
| 75 | + /Root 1 0 R | ||
| 76 | + /Nesting [ [ [ [ [ /1 !2 !3 !4 /5 /6 /7 /8 /9 /10 ] ] ] ] ] | ||
| 77 | +>> | ||
| 78 | +startxref | ||
| 79 | +55 | ||
| 80 | +%%EOF |