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 | 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 | 327 | class Config |
| 310 | 328 | { |
| 311 | 329 | friend class QPDFJob; |
| ... | ... | @@ -331,6 +349,8 @@ class QPDFJob |
| 331 | 349 | QPDF_DLL |
| 332 | 350 | std::shared_ptr<AttConfig> addAttachment(); |
| 333 | 351 | QPDF_DLL |
| 352 | + std::shared_ptr<GlobalConfig> global(); | |
| 353 | + QPDF_DLL | |
| 334 | 354 | std::shared_ptr<PagesConfig> pages(); |
| 335 | 355 | QPDF_DLL |
| 336 | 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 | 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 | 149 | /// parsing. |
| 150 | 150 | /// |
| 151 | 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 | 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 | 166 | /// The limit applies when the PDF document's xref table is undamaged and the object itself |
| 166 | 167 | /// can be parsed without errors. The default limit is 4,294,967,295. |
| ... | ... | @@ -178,8 +179,7 @@ namespace qpdf::global |
| 178 | 179 | /// parsing objects. |
| 179 | 180 | /// |
| 180 | 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 | 184 | /// @return The maximum number of top-level objects allowed in a container while parsing |
| 185 | 185 | /// objects. | ... | ... |
job.sums
| ... | ... | @@ -4,17 +4,18 @@ generate_auto_job 8e3175a515aa8837d8a01bba0346b04b3d777d70330ba5b7d52f691316054a |
| 4 | 4 | include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 |
| 5 | 5 | include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 |
| 6 | 6 | include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5 |
| 7 | +include/qpdf/auto_job_c_global.hh f1dc365206d033a0d6b19b6e561cc244fbd5b49a8d9604b5b646a5fd92895a5a | |
| 7 | 8 | include/qpdf/auto_job_c_main.hh b865eb827356554763bb8349eadfcbc5cb260f80e025a5e229467c525007356d |
| 8 | 9 | include/qpdf/auto_job_c_pages.hh 09ca15649cc94fdaf6d9bdae28a20723f2a66616bf15aa86d83df31051d82506 |
| 9 | 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 | 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 | 21 | manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b | ... | ... |
job.yml
| ... | ... | @@ -84,12 +84,24 @@ options: |
| 84 | 84 | - zopfli |
| 85 | 85 | optional_choices: |
| 86 | 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 | 98 | - table: main |
| 88 | 99 | config: c_main |
| 89 | 100 | manual: |
| 90 | 101 | - add-attachment |
| 91 | 102 | - copy-attachments-from |
| 92 | 103 | - encrypt |
| 104 | + - global | |
| 93 | 105 | - overlay |
| 94 | 106 | - pages |
| 95 | 107 | - underlay |
| ... | ... | @@ -112,6 +124,7 @@ options: |
| 112 | 124 | - filtered-stream-data |
| 113 | 125 | - flatten-rotation |
| 114 | 126 | - generate-appearances |
| 127 | + - global | |
| 115 | 128 | - ignore-xref-streams |
| 116 | 129 | - is-encrypted |
| 117 | 130 | - json-input |
| ... | ... | @@ -399,6 +412,13 @@ json: |
| 399 | 412 | - null |
| 400 | 413 | json-stream-data: |
| 401 | 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 | 422 | # other options |
| 403 | 423 | update-from-json: |
| 404 | 424 | allow-weak-crypto: | ... | ... |
libqpdf/QPDFJob_argv.cc
| ... | ... | @@ -31,6 +31,7 @@ namespace |
| 31 | 31 | std::shared_ptr<QPDFJob::Config> c_main; |
| 32 | 32 | std::shared_ptr<QPDFJob::CopyAttConfig> c_copy_att; |
| 33 | 33 | std::shared_ptr<QPDFJob::AttConfig> c_att; |
| 34 | + std::shared_ptr<QPDFJob::GlobalConfig> c_global; | |
| 34 | 35 | std::shared_ptr<QPDFJob::PagesConfig> c_pages; |
| 35 | 36 | std::shared_ptr<QPDFJob::UOConfig> c_uo; |
| 36 | 37 | std::shared_ptr<QPDFJob::EncConfig> c_enc; |
| ... | ... | @@ -418,6 +419,21 @@ ArgParser::argEndSetPageLabels() |
| 418 | 419 | } |
| 419 | 420 | |
| 420 | 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 | 437 | ArgParser::argJobJsonHelp() |
| 422 | 438 | { |
| 423 | 439 | *QPDFLogger::defaultLogger()->getInfo() | ... | ... |
libqpdf/QPDFJob_config.cc
| ... | ... | @@ -4,31 +4,53 @@ |
| 4 | 4 | #include <qpdf/QPDFUsage.hh> |
| 5 | 5 | #include <qpdf/QTC.hh> |
| 6 | 6 | #include <qpdf/QUtil.hh> |
| 7 | +#include <qpdf/Util.hh> | |
| 8 | +#include <qpdf/global_private.hh> | |
| 7 | 9 | |
| 8 | 10 | #include <concepts> |
| 9 | 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 | 17 | throw QPDFUsage( |
| 15 | 18 | "invalid "s.append(option) + ": must be a number between " + std::to_string(min) + " and " + |
| 16 | 19 | std::to_string(max)); |
| 17 | 20 | } |
| 18 | 21 | |
| 19 | 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 | 26 | try { |
| 24 | - result = std::stoi(value); | |
| 27 | + int result = std::stoi(value); | |
| 25 | 28 | if (result < min || result > max) { |
| 26 | - int_usage(option, min, max); | |
| 29 | + int_usage(option, max, min); | |
| 27 | 30 | } |
| 31 | + return result; | |
| 28 | 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 | 56 | void |
| ... | ... | @@ -156,14 +178,14 @@ QPDFJob::Config::compressStreams(std::string const& parameter) |
| 156 | 178 | QPDFJob::Config* |
| 157 | 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 | 182 | return this; |
| 161 | 183 | } |
| 162 | 184 | |
| 163 | 185 | QPDFJob::Config* |
| 164 | 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 | 189 | return this; |
| 168 | 190 | } |
| 169 | 191 | |
| ... | ... | @@ -1140,6 +1162,60 @@ QPDFJob::Config::encrypt( |
| 1140 | 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 | 1219 | QPDFJob::Config* |
| 1144 | 1220 | QPDFJob::Config::setPageLabels(const std::vector<std::string>& specs) |
| 1145 | 1221 | { | ... | ... |
libqpdf/QPDFJob_json.cc
| ... | ... | @@ -63,6 +63,7 @@ namespace |
| 63 | 63 | std::shared_ptr<QPDFJob::Config> c_main; |
| 64 | 64 | std::shared_ptr<QPDFJob::CopyAttConfig> c_copy_att; |
| 65 | 65 | std::shared_ptr<QPDFJob::AttConfig> c_att; |
| 66 | + std::shared_ptr<QPDFJob::GlobalConfig> c_global; | |
| 66 | 67 | std::shared_ptr<QPDFJob::PagesConfig> c_pages; |
| 67 | 68 | std::shared_ptr<QPDFJob::UOConfig> c_uo; |
| 68 | 69 | std::shared_ptr<QPDFJob::EncConfig> c_enc; |
| ... | ... | @@ -620,6 +621,19 @@ Handlers::beginSetPageLabelsArray(JSON) |
| 620 | 621 | } |
| 621 | 622 | |
| 622 | 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 | 637 | QPDFJob::initializeFromJson(std::string const& json, bool partial) |
| 624 | 638 | { |
| 625 | 639 | std::list<std::string> errors; | ... | ... |
libqpdf/qpdf/auto_job_decl.hh
| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | // |
| 6 | 6 | // clang-format off |
| 7 | 7 | // |
| 8 | +static constexpr char const* O_GLOBAL = "global"; | |
| 8 | 9 | static constexpr char const* O_PAGES = "pages"; |
| 9 | 10 | static constexpr char const* O_ENCRYPTION = "encryption"; |
| 10 | 11 | static constexpr char const* O_40_BIT_ENCRYPTION = "40-bit encryption"; |
| ... | ... | @@ -21,11 +22,13 @@ void argShowCrypto(); |
| 21 | 22 | void argJobJsonHelp(); |
| 22 | 23 | void argZopfli(); |
| 23 | 24 | void argJsonHelp(std::string const&); |
| 25 | +void argEndGlobal(); | |
| 24 | 26 | void argPositional(std::string const&); |
| 25 | 27 | void argAddAttachment(); |
| 26 | 28 | void argCopyAttachmentsFrom(); |
| 27 | 29 | void argEmpty(); |
| 28 | 30 | void argEncrypt(); |
| 31 | +void argGlobal(); | |
| 29 | 32 | void argOverlay(); |
| 30 | 33 | void argPages(); |
| 31 | 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 | 1004 | chapter of the manual for information about how to use this |
| 1005 | 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 | 1047 | ap.addHelpTopic("testing", "options for testing or debugging", R"(The options below are useful when writing automated test code that |
| 1008 | 1048 | includes files created by qpdf or when testing qpdf itself. |
| 1009 | 1049 | )"); |
| ... | ... | @@ -1039,6 +1079,7 @@ static void add_help(QPDFArgParser& ap) |
| 1039 | 1079 | add_help_6(ap); |
| 1040 | 1080 | add_help_7(ap); |
| 1041 | 1081 | add_help_8(ap); |
| 1082 | + add_help_9(ap); | |
| 1042 | 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 | 34 | this->ap.addBare("job-json-help", b(&ArgParser::argJobJsonHelp)); |
| 35 | 35 | this->ap.addBare("zopfli", b(&ArgParser::argZopfli)); |
| 36 | 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 | 43 | this->ap.selectMainOptionTable(); |
| 38 | 44 | this->ap.addPositional(p(&ArgParser::argPositional)); |
| 39 | 45 | this->ap.addBare("add-attachment", b(&ArgParser::argAddAttachment)); |
| ... | ... | @@ -50,6 +56,7 @@ this->ap.addBare("externalize-inline-images", [this](){c_main->externalizeInline |
| 50 | 56 | this->ap.addBare("filtered-stream-data", [this](){c_main->filteredStreamData();}); |
| 51 | 57 | this->ap.addBare("flatten-rotation", [this](){c_main->flattenRotation();}); |
| 52 | 58 | this->ap.addBare("generate-appearances", [this](){c_main->generateAppearances();}); |
| 59 | +this->ap.addBare("global", b(&ArgParser::argGlobal)); | |
| 53 | 60 | this->ap.addBare("ignore-xref-streams", [this](){c_main->ignoreXrefStreams();}); |
| 54 | 61 | this->ap.addBare("is-encrypted", [this](){c_main->isEncrypted();}); |
| 55 | 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 | 24 | void endJsonKeyArray(); |
| 25 | 25 | void beginJsonObjectArray(JSON); |
| 26 | 26 | void endJsonObjectArray(); |
| 27 | +void beginGlobal(JSON); | |
| 28 | +void endGlobal(); | |
| 27 | 29 | void beginAddAttachmentArray(JSON); |
| 28 | 30 | void endAddAttachmentArray(); |
| 29 | 31 | void beginAddAttachment(JSON); | ... | ... |
libqpdf/qpdf/auto_job_json_init.hh
| ... | ... | @@ -272,6 +272,24 @@ popHandler(); // key: jsonStreamData |
| 272 | 272 | pushKey("jsonStreamPrefix"); |
| 273 | 273 | addParameter([this](std::string const& p) { c_main->jsonStreamPrefix(p); }); |
| 274 | 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 | 293 | pushKey("updateFromJson"); |
| 276 | 294 | addParameter([this](std::string const& p) { c_main->updateFromJson(p); }); |
| 277 | 295 | popHandler(); // key: updateFromJson | ... | ... |
libqpdf/qpdf/auto_job_schema.hh
| ... | ... | @@ -90,6 +90,13 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({ |
| 90 | 90 | ], |
| 91 | 91 | "jsonStreamData": "how to handle streams in json output", |
| 92 | 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 | 100 | "updateFromJson": "update a PDF from qpdf JSON", |
| 94 | 101 | "allowWeakCrypto": "allow insecure cryptographic algorithms", |
| 95 | 102 | "keepFilesOpen": "manage keeping multiple files open", | ... | ... |
libtests/objects.cc
| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | #include <qpdf/QPDF.hh> |
| 6 | 6 | |
| 7 | 7 | #include <qpdf/QIntC.hh> |
| 8 | +#include <qpdf/QPDFJob.hh> | |
| 8 | 9 | #include <qpdf/QPDFObjectHandle_private.hh> |
| 9 | 10 | #include <qpdf/QUtil.hh> |
| 10 | 11 | #include <qpdf/global.hh> |
| ... | ... | @@ -237,6 +238,47 @@ test_2(QPDF& pdf, char const* arg2) |
| 237 | 238 | } catch (std::exception&) { |
| 238 | 239 | } |
| 239 | 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 | 284 | void | ... | ... |
manual/cli.rst
| ... | ... | @@ -3762,6 +3762,110 @@ Related Options |
| 3762 | 3762 | For a information about how to use this option, please see |
| 3763 | 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 | 3869 | .. _test-options: |
| 3766 | 3870 | |
| 3767 | 3871 | Options for Testing or Debugging | ... | ... |
manual/qpdf.1
| ... | ... | @@ -1191,6 +1191,51 @@ how to use this option. |
| 1191 | 1191 | Update a PDF file from a JSON file. Please see the "qpdf JSON" |
| 1192 | 1192 | chapter of the manual for information about how to use this |
| 1193 | 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 | 1239 | .SH TESTING (options for testing or debugging) |
| 1195 | 1240 | The options below are useful when writing automated test code that |
| 1196 | 1241 | includes files created by qpdf or when testing qpdf itself. | ... | ... |
qpdf/qtest/arg-parsing.test
| ... | ... | @@ -15,7 +15,7 @@ cleanup(); |
| 15 | 15 | |
| 16 | 16 | my $td = new TestDriver('arg-parsing'); |
| 17 | 17 | |
| 18 | -my $n_tests = 32; | |
| 18 | +my $n_tests = 33; | |
| 19 | 19 | |
| 20 | 20 | $td->runtest("required argument", |
| 21 | 21 | {$td->COMMAND => "qpdf --password minimal.pdf"}, |
| ... | ... | @@ -187,5 +187,12 @@ $td->runtest("bad jpeg-quality", |
| 187 | 187 | $td->EXIT_STATUS => 2}, |
| 188 | 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 | 197 | cleanup(); |
| 191 | 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 | ... | ... |