Commit 34db6e3057d1b0c5afdcc60b570fdbe8ce711f8a

Authored by m-holger
1 parent 04b18627

Introduce `global` namespace for managing qpdf global options and limits; add su…

…pport for configurable global limits via `qpdf_global_get_uint32` and `qpdf_global_set_uint32`.
include/qpdf/Constants.h
... ... @@ -244,4 +244,47 @@ enum qpdf_page_label_e {
244 244 pl_roman_upper,
245 245 };
246 246  
  247 +/**
  248 + * @enum qpdf_result_e
  249 + * @brief Enum representing result codes for qpdf C-API functions.
  250 + *
  251 + * Results <= qpdf_r_no_warn indicate success without warnings,
  252 + * qpdf_r_no_warn < result <= qpdf_r_success indicates success with warnings, and
  253 + * qpdf_r_success < result indicates failure.
  254 + */
  255 +enum qpdf_result_e {
  256 + /* success */
  257 + qpdf_r_ok = 0,
  258 + qpdf_r_no_warn = 0xff, /// any result <= qpdf_no_warn indicates success without warning
  259 + qpdf_r_success = 0xffff, /// any result <= qpdf_no_warn indicates success
  260 + /* failure */
  261 + qpdf_r_bad_parameter = 0x10000,
  262 +
  263 + qpdf_r_no_warn_mask = 0x7fffff00,
  264 + qpdf_r_success_mask = 0x7fff0000,
  265 +};
  266 +
  267 +/**
  268 + * @enum qpdf_param_e
  269 + * @brief This enumeration defines various parameters and configuration options for qpdf C-API
  270 + * functions.
  271 + *
  272 + * The enum values are grouped into sections based on their functionality, such as global
  273 + * options or global limits.For the meaning of individual parameters see `qpdf/global.cc`
  274 + */
  275 +enum qpdf_param_e {
  276 + /* global options */
  277 + qpdf_p_default_limits = 0x10100,
  278 + /* global limits */
  279 +
  280 + /* object - parser limits */
  281 + qpdf_p_objects_max_nesting = 0x11000,
  282 + qpdf_p_objects_max_errors,
  283 + qpdf_p_objects_max_container_size,
  284 + qpdf_p_objects_max_container_size_damaged,
  285 +
  286 + /* next section = 0x20000 */
  287 + qpdf_enum_max = 0x7fffffff,
  288 +};
  289 +
247 290 #endif /* QPDFCONSTANTS_H */
... ...
include/qpdf/QUtil.hh
... ... @@ -20,8 +20,10 @@
20 20 #ifndef QUTIL_HH
21 21 #define QUTIL_HH
22 22  
  23 +#include <qpdf/Constants.h>
23 24 #include <qpdf/DLL.h>
24 25 #include <qpdf/Types.h>
  26 +
25 27 #include <cstdio>
26 28 #include <cstring>
27 29 #include <ctime>
... ... @@ -441,6 +443,25 @@ namespace QUtil
441 443 QPDF_DLL
442 444 bool is_number(char const*);
443 445  
  446 + /// @brief Handles the result code from qpdf functions.
  447 + ///
  448 + /// **For qpdf internal use only - not part of the public API**
  449 + /// @par
  450 + /// Depending on the result code, either continues execution, checks or throws an
  451 + /// exception in case of an invalid parameter.
  452 + ///
  453 + /// @param result The result code of type qpdf_result_e, indicating success or failure status.
  454 + /// @param context A string describing the context where this function is invoked, used for
  455 + /// error reporting if an exception is thrown.
  456 + ///
  457 + /// @throws std::logic_error If the result code is `qpdf_bad_parameter`, indicating an invalid
  458 + /// parameter was supplied to a function. The exception message will
  459 + /// include the provided context for easier debugging.
  460 + ///
  461 + /// @since 12.3
  462 + QPDF_DLL
  463 + void handle_result_code(qpdf_result_e result, std::string_view context);
  464 +
444 465 // This method parses the numeric range syntax used by the qpdf command-line tool. May throw
445 466 // std::runtime_error. A numeric range is as comma-separated list of groups. A group may be a
446 467 // number specification or a range of number specifications separated by a dash. A number
... ...
include/qpdf/global.hh 0 → 100644
  1 +// Copyright (c) 2005-2021 Jay Berkenbilt
  2 +// Copyright (c) 2022-2025 Jay Berkenbilt and Manfred Holger
  3 +//
  4 +// This file is part of qpdf.
  5 +//
  6 +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
  7 +// in compliance with the License. You may obtain a copy of the License at
  8 +//
  9 +// http://www.apache.org/licenses/LICENSE-2.0
  10 +//
  11 +// Unless required by applicable law or agreed to in writing, software distributed under the License
  12 +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
  13 +// or implied. See the License for the specific language governing permissions and limitations under
  14 +// the License.
  15 +//
  16 +// Versions of qpdf prior to version 7 were released under the terms of version 2.0 of the Artistic
  17 +// License. At your option, you may continue to consider qpdf to be licensed under those terms.
  18 +// Please see the manual for additional information.
  19 +
  20 +#ifndef GLOBAL_HH
  21 +#define GLOBAL_HH
  22 +
  23 +#include <qpdf/Constants.h>
  24 +
  25 +#include <qpdf/QUtil.hh>
  26 +#include <qpdf/qpdf-c.h>
  27 +
  28 +#include <cstdint>
  29 +
  30 +namespace qpdf::global
  31 +{
  32 + /// Helper function to translate result codes into C++ exceptions - for qpdf internal use only.
  33 + inline void
  34 + handle_result(qpdf_result_e result)
  35 + {
  36 + if (result != qpdf_r_ok) {
  37 + QUtil::handle_result_code(result, "qpdf::global");
  38 + }
  39 + }
  40 +
  41 + /// Helper function to wrap calls to qpdf_global_get_uint32 - for qpdf internal use only.
  42 + inline uint32_t
  43 + get_uint32(qpdf_param_e param)
  44 + {
  45 + uint32_t value;
  46 + handle_result(qpdf_global_get_uint32(param, &value));
  47 + return value;
  48 + }
  49 +
  50 + /// Helper function to wrap calls to qpdf_global_set_uint32 - for qpdf internal use only.
  51 + inline void
  52 + set_uint32(qpdf_param_e param, uint32_t value)
  53 + {
  54 + handle_result(qpdf_global_set_uint32(param, value));
  55 + }
  56 +
  57 + namespace options
  58 + {
  59 + /// @brief Retrieves whether default limits are enabled.
  60 + ///
  61 + /// @return True if default limits are enabled.
  62 + ///
  63 + /// @since 12.3
  64 + bool inline default_limits()
  65 + {
  66 + return get_uint32(qpdf_p_default_limits) != 0;
  67 + }
  68 +
  69 + /// @brief Disable all optional default limits if `false` is passed.
  70 + ///
  71 + /// This function disables all optional default limits if `false` is passed. Once default
  72 + /// values have been disabled they cannot be re-enabled. Passing `true` has no effect. This
  73 + /// function will leave any limits that have been explicitly set unchanged. Some limits,
  74 + /// such as limits imposed to avoid stack overflows, cannot be disabled but can be changed.
  75 + ///
  76 + /// @param value A boolean indicating whether to disable (false) the default limits.
  77 + ///
  78 + /// @since 12.3
  79 + void inline default_limits(bool value)
  80 + {
  81 + set_uint32(qpdf_p_default_limits, value ? QPDF_TRUE : QPDF_FALSE);
  82 + }
  83 +
  84 + } // namespace options
  85 +
  86 + namespace limits
  87 + {
  88 + /// @brief Retrieves the maximum nesting level while parsing objects.
  89 + ///
  90 + /// @return The maximum nesting level while parsing objects.
  91 + ///
  92 + /// @note The maximum nesting level cannot be disabled by calling `default_limit(false)`.
  93 + ///
  94 + /// @since 12.3
  95 + uint32_t inline objects_max_nesting()
  96 + {
  97 + return get_uint32(qpdf_p_objects_max_nesting);
  98 + }
  99 +
  100 + /// @brief Sets the maximum nesting level while parsing objects.
  101 + ///
  102 + /// @param value The maximum nesting level to set.
  103 + ///
  104 + /// @note The maximum nesting level cannot be disabled by calling `default_limit(false)`.
  105 + ///
  106 + /// @since 12.3
  107 + void inline objects_max_nesting(uint32_t value)
  108 + {
  109 + set_uint32(qpdf_p_objects_max_nesting, value);
  110 + }
  111 +
  112 + /// @brief Retrieves the maximum number of errors allowed while parsing objects.
  113 + ///
  114 + /// A value of 0 means that there is no maximum imposed.
  115 + ///
  116 + /// @return The maximum number of errors allowed while parsing objects.
  117 + ///
  118 + /// @since 12.3
  119 + uint32_t inline objects_max_errors()
  120 + {
  121 + return get_uint32(qpdf_p_objects_max_errors);
  122 + }
  123 +
  124 + /// Sets the maximum number of errors allowed while parsing objects.
  125 + ///
  126 + /// A value of 0 means that there is no maximum imposed.
  127 + ///
  128 + /// @param value The maximum number of errors allowed while parsing objects to set.
  129 + ///
  130 + /// @since 12.3
  131 + void inline objects_max_errors(uint32_t value)
  132 + {
  133 + set_uint32(qpdf_p_objects_max_errors, value);
  134 + }
  135 +
  136 + /// @brief Retrieves the maximum number of objectstop-level allowed in a container while
  137 + /// parsing.
  138 + ///
  139 + /// The limit applies when the PDF document's xref table is undamaged and the object itself
  140 + /// can be parsed without errors. The default limit is 4,294,967,295.
  141 + ///
  142 + /// @return The maximum number of top-level objects allowed in a container while parsing
  143 + /// objects.
  144 + ///
  145 + /// @since 12.3
  146 + uint32_t inline objects_max_container_size()
  147 + {
  148 + return get_uint32(qpdf_p_objects_max_container_size);
  149 + }
  150 +
  151 + /// @brief Sets the maximum number oftop-level objects allowed in a container while parsing.
  152 + ///
  153 + /// The limit applies when the PDF document's xref table is undamaged and the object itself
  154 + /// can be parsed without errors. The default limit is 4,294,967,295.
  155 + ///
  156 + /// @param value The maximum number of top-level objects allowed in a container while
  157 + /// parsing objects to set.
  158 + ///
  159 + /// @since 12.3
  160 + void inline objects_max_container_size(uint32_t value)
  161 + {
  162 + set_uint32(qpdf_p_objects_max_container_size, value);
  163 + }
  164 +
  165 + /// @brief Retrieves the maximum number of top-level objects allowed in a container while
  166 + /// parsing objects.
  167 + ///
  168 + /// The limit applies when the PDF document's xref table is damaged or the object itself is
  169 + /// damaged. The limit also applies when parsing trailer dictionaries and xref streams. The
  170 + /// default limit is 5,000.
  171 + ///
  172 + /// @return The maximum number of top-level objects allowed in a container while parsing
  173 + /// objects.
  174 + ///
  175 + /// @since 12.3
  176 + uint32_t inline objects_max_container_size_damaged()
  177 + {
  178 + return get_uint32(qpdf_p_objects_max_container_size_damaged);
  179 + }
  180 +
  181 + /// @brief Sets the maximum number of top-level objects allowed in a container while
  182 + /// parsing.
  183 + ///
  184 + /// The limit applies when the PDF document's xref table is damaged or the object itself is
  185 + /// damaged. The limit also applies when parsing trailer dictionaries and xref streams. The
  186 + /// default limit is 5,000.
  187 + ///
  188 + /// @param value The maximum number of top-level objects allowed in a container while
  189 + /// parsing objects to set.
  190 + ///
  191 + /// @since 12.3
  192 + void inline objects_max_container_size_damaged(uint32_t value)
  193 + {
  194 + set_uint32(qpdf_p_objects_max_container_size_damaged, value);
  195 + }
  196 + } // namespace limits
  197 +
  198 +} // namespace qpdf::global
  199 +
  200 +#endif // GLOBAL_HH
... ...
include/qpdf/qpdf-c.h
... ... @@ -119,6 +119,8 @@
119 119 #include <qpdf/DLL.h>
120 120 #include <qpdf/Types.h>
121 121 #include <qpdf/qpdflogger-c.h>
  122 +
  123 +#include <stdint.h>
122 124 #include <string.h>
123 125  
124 126 #ifdef __cplusplus
... ... @@ -1000,6 +1002,50 @@ extern &quot;C&quot; {
1000 1002 /* removePage() */
1001 1003 QPDF_DLL
1002 1004 QPDF_ERROR_CODE qpdf_remove_page(qpdf_data qpdf, qpdf_oh page);
  1005 +
  1006 + /* GLOBAL OPTIONS AND SETTINGS */
  1007 +
  1008 + QPDF_DLL
  1009 + /**
  1010 + * @brief Retrieves a 32-bit unsigned integer value associated with a global option or limit.
  1011 + *
  1012 + * This function allows querying of specific parameters, identified by the qpdf_param_e enum,
  1013 + * and retrieves their associated unsigned 32-bit integer values. The result will be stored in
  1014 + * the variable pointed to by `value`. For details about the available parameters and their
  1015 + * meanings see `qpdf/global.hh`.
  1016 + *
  1017 + * @param param[in] The parameter for which the value is being retrieved. This must be a valid
  1018 + * value from the qpdf_param_e enumeration.
  1019 + * @param value[out] A pointer to a uint32_t to store the retrieved value. This must be a valid,
  1020 + * non-null pointer.
  1021 + *
  1022 + * @return An enumeration of type qpdf_result_e indicating the result of the operation. Possible
  1023 + * values include success or specific error statuses related to the retrieval process.
  1024 + *
  1025 + * @since 12.3
  1026 + */
  1027 + enum qpdf_result_e qpdf_global_get_uint32(enum qpdf_param_e param, uint32_t* value);
  1028 +
  1029 + QPDF_DLL
  1030 + /**
  1031 + * @brief Sets a global option or limit for the qpdf library to a specified value.
  1032 + *
  1033 + * This function is used to configure global options or limits for the qpdf library based on the
  1034 + * provided parameter and value. The behavior depends on the specific `param` provided and its
  1035 + * valid range of values. For details about the available parameters and their meanings see
  1036 + * `qpdf/global.hh`.
  1037 + *
  1038 + * @param param[in] The parameter to be set. Must be one of the values defined in the
  1039 + * qpdf_param_e enumeration.
  1040 + * @param value[in] The value to assign to the specified parameter. Interpretation of this value
  1041 + * depends on the parameter being set.
  1042 + *
  1043 + * @return An enumeration of type qpdf_result_e indicating the result of the operation. Possible
  1044 + * values include success or specific error statuses related to the retrieval process.
  1045 + *
  1046 + * @since 12.3
  1047 + */
  1048 + enum qpdf_result_e qpdf_global_set_uint32(enum qpdf_param_e param, uint32_t value);
1003 1049 #ifdef __cplusplus
1004 1050 }
1005 1051  
... ...
libqpdf/QUtil.cc
... ... @@ -40,6 +40,7 @@
40 40 #endif
41 41  
42 42 using namespace qpdf;
  43 +using namespace std::literals;
43 44  
44 45 // First element is 24
45 46 static unsigned short pdf_doc_low_to_unicode[] = {
... ... @@ -2068,3 +2069,15 @@ QUtil::is_hex_digit(char c)
2068 2069 {
2069 2070 return util::is_hex_digit(c);
2070 2071 }
  2072 +
  2073 +void
  2074 +QUtil::handle_result_code(qpdf_result_e result, std::string_view context)
  2075 +{
  2076 + if (result == qpdf_r_ok) {
  2077 + return;
  2078 + }
  2079 + qpdf::util::assertion(
  2080 + result == qpdf_r_bad_parameter,
  2081 + "unexpected result code received from function in "s.append(context));
  2082 + throw std::logic_error("invalid parameter supplied to function in "s.append(context));
  2083 +}
... ...
libqpdf/global.cc
1 1 #include <qpdf/global_private.hh>
2 2  
  3 +#include <qpdf/Util.hh>
  4 +
3 5 using namespace qpdf;
  6 +using namespace qpdf::global;
  7 +
  8 +Limits Limits::l;
  9 +Options Options::o;
  10 +
  11 +void
  12 +Limits::objects_max_container_size(bool damaged, uint32_t value)
  13 +{
  14 + if (damaged) {
  15 + l.objects_max_container_size_damaged_set_ = true;
  16 + l.objects_max_container_size_damaged_ = value;
  17 + } else {
  18 + l.objects_max_container_size_ = value;
  19 + }
  20 +}
  21 +
  22 +void
  23 +Limits::disable_defaults()
  24 +{
  25 + if (!l.objects_max_errors_set_) {
  26 + l.objects_max_errors_ = 0;
  27 + }
  28 + if (!l.objects_max_container_size_damaged_set_) {
  29 + l.objects_max_container_size_damaged_ = std::numeric_limits<uint32_t>::max();
  30 + }
  31 +}
  32 +
  33 +qpdf_result_e
  34 +qpdf_global_get_uint32(qpdf_param_e param, uint32_t* value)
  35 +{
  36 + qpdf_expect(value);
  37 + switch (param) {
  38 + case qpdf_p_default_limits:
  39 + *value = Options::default_limits();
  40 + return qpdf_r_ok;
  41 + case qpdf_p_objects_max_nesting:
  42 + *value = Limits::objects_max_nesting();
  43 + return qpdf_r_ok;
  44 + case qpdf_p_objects_max_errors:
  45 + *value = Limits::objects_max_errors();
  46 + return qpdf_r_ok;
  47 + case qpdf_p_objects_max_container_size:
  48 + *value = Limits::objects_max_container_size(false);
  49 + return qpdf_r_ok;
  50 + case qpdf_p_objects_max_container_size_damaged:
  51 + *value = Limits::objects_max_container_size(true);
  52 + return qpdf_r_ok;
  53 + default:
  54 + return qpdf_r_bad_parameter;
  55 + }
  56 +}
4 57  
5   -global::Limits global::Limits::l;
  58 +qpdf_result_e
  59 +qpdf_global_set_uint32(qpdf_param_e param, uint32_t value)
  60 +{
  61 + switch (param) {
  62 + case qpdf_p_default_limits:
  63 + Options::default_limits(value);
  64 + return qpdf_r_ok;
  65 + case qpdf_p_objects_max_nesting:
  66 + Limits::objects_max_nesting(value);
  67 + return qpdf_r_ok;
  68 + case qpdf_p_objects_max_errors:
  69 + Limits::objects_max_errors(value);
  70 + return qpdf_r_ok;
  71 + case qpdf_p_objects_max_container_size:
  72 + Limits::objects_max_container_size(false, value);
  73 + return qpdf_r_ok;
  74 + case qpdf_p_objects_max_container_size_damaged:
  75 + Limits::objects_max_container_size(true, value);
  76 + return qpdf_r_ok;
  77 + default:
  78 + return qpdf_r_bad_parameter;
  79 + }
  80 +}
... ...
libqpdf/qpdf/global_private.hh
1   -
2 1 #ifndef GLOBAL_PRIVATE_HH
3 2 #define GLOBAL_PRIVATE_HH
4 3  
5   -#include <qpdf/Constants.h>
  4 +#include <qpdf/global.hh>
6 5  
7   -#include <cstdint>
8 6 #include <limits>
9 7  
10   -namespace qpdf
  8 +namespace qpdf::global
11 9 {
12   - namespace global
  10 + class Limits
13 11 {
14   - class Limits
  12 + public:
  13 + Limits(Limits const&) = delete;
  14 + Limits(Limits&&) = delete;
  15 + Limits& operator=(Limits const&) = delete;
  16 + Limits& operator=(Limits&&) = delete;
  17 +
  18 + static uint32_t const&
  19 + objects_max_nesting()
15 20 {
16   - public:
17   - Limits(Limits const&) = delete;
18   - Limits(Limits&&) = delete;
19   - Limits& operator=(Limits const&) = delete;
20   - Limits& operator=(Limits&&) = delete;
21   -
22   - static uint32_t const&
23   - objects_max_nesting()
24   - {
25   - return l.objects_max_nesting_;
26   - }
  21 + return l.objects_max_nesting_;
  22 + }
27 23  
28   - static uint32_t const&
29   - objects_max_errors()
30   - {
31   - return l.objects_max_errors_;
32   - }
  24 + static void
  25 + objects_max_nesting(uint32_t value)
  26 + {
  27 + l.objects_max_nesting_ = value;
  28 + }
33 29  
34   - static uint32_t const&
35   - objects_max_container_size(bool damaged)
36   - {
37   - return damaged ? l.objects_max_container_size_damaged_
38   - : l.objects_max_container_size_;
39   - }
  30 + static uint32_t const&
  31 + objects_max_errors()
  32 + {
  33 + return l.objects_max_errors_;
  34 + }
40 35  
41   - private:
42   - Limits() = default;
43   - ~Limits() = default;
  36 + static void
  37 + objects_max_errors(uint32_t value)
  38 + {
  39 + l.objects_max_errors_set_ = true;
  40 + l.objects_max_errors_ = value;
  41 + }
  42 +
  43 + static uint32_t const&
  44 + objects_max_container_size(bool damaged)
  45 + {
  46 + return damaged ? l.objects_max_container_size_damaged_ : l.objects_max_container_size_;
  47 + }
44 48  
45   - static Limits l;
  49 + static void objects_max_container_size(bool damaged, uint32_t value);
46 50  
47   - uint32_t objects_max_nesting_{499};
48   - uint32_t objects_max_errors_{15};
49   - uint32_t objects_max_container_size_{std::numeric_limits<uint32_t>::max()};
50   - uint32_t objects_max_container_size_damaged_{5'000};
51   - };
  51 + static void disable_defaults();
  52 +
  53 + private:
  54 + Limits() = default;
  55 + ~Limits() = default;
  56 +
  57 + static Limits l;
  58 +
  59 + uint32_t objects_max_nesting_{499};
  60 + uint32_t objects_max_errors_{15};
  61 + bool objects_max_errors_set_{false};
  62 + uint32_t objects_max_container_size_{std::numeric_limits<uint32_t>::max()};
  63 + uint32_t objects_max_container_size_damaged_{5'000};
  64 + bool objects_max_container_size_damaged_set_{false};
  65 + };
  66 +
  67 + class Options
  68 + {
  69 + public:
  70 + static bool
  71 + default_limits()
  72 + {
  73 + return static_cast<bool>(o.default_limits_);
  74 + }
  75 +
  76 + static void
  77 + default_limits(bool value)
  78 + {
  79 + if (!value) {
  80 + o.default_limits_ = false;
  81 + Limits::disable_defaults();
  82 + }
  83 + }
52 84  
53   - } // namespace global
  85 + private:
  86 + static Options o;
54 87  
55   -} // namespace qpdf
  88 + bool default_limits_{true};
  89 + };
  90 +} // namespace qpdf::global
56 91  
57 92 #endif // GLOBAL_PRIVATE_HH
... ...
libtests/objects.cc
... ... @@ -7,6 +7,7 @@
7 7 #include <qpdf/QIntC.hh>
8 8 #include <qpdf/QPDFObjectHandle_private.hh>
9 9 #include <qpdf/QUtil.hh>
  10 +#include <qpdf/global.hh>
10 11  
11 12 #include <climits>
12 13 #include <cstdio>
... ... @@ -153,6 +154,75 @@ test_1(QPDF&amp; pdf, char const* arg2)
153 154 assert(QPDFObjectHandle(d).getDictAsMap().size() == 4);
154 155 }
155 156  
  157 +static void
  158 +test_2(QPDF& pdf, char const* arg2)
  159 +{
  160 + // Test global limits.
  161 + using namespace qpdf::global::options;
  162 + using namespace qpdf::global::limits;
  163 +
  164 + // Check default values
  165 + assert(objects_max_nesting() == 499);
  166 + assert(objects_max_errors() == 15);
  167 + assert(objects_max_container_size() == std::numeric_limits<uint32_t>::max());
  168 + assert(objects_max_container_size_damaged() == 5'000);
  169 + assert(default_limits());
  170 +
  171 + // Test disabling optional default limits
  172 + default_limits(false);
  173 + assert(objects_max_nesting() == 499);
  174 + assert(objects_max_errors() == 0);
  175 + assert(objects_max_container_size() == std::numeric_limits<uint32_t>::max());
  176 + assert(objects_max_container_size_damaged() == std::numeric_limits<uint32_t>::max());
  177 + assert(!default_limits());
  178 +
  179 + // Check disabling default limits is irreversible
  180 + default_limits(true);
  181 + assert(!default_limits());
  182 +
  183 + // Test setting limits
  184 + objects_max_nesting(11);
  185 + objects_max_errors(12);
  186 + objects_max_container_size(13);
  187 + objects_max_container_size_damaged(14);
  188 +
  189 + assert(objects_max_nesting() == 11);
  190 + assert(objects_max_errors() == 12);
  191 + assert(objects_max_container_size() == 13);
  192 + assert(objects_max_container_size_damaged() == 14);
  193 +
  194 + // Check disabling default limits does not override explicit limits
  195 + default_limits(false);
  196 + assert(objects_max_nesting() == 11);
  197 + assert(objects_max_errors() == 12);
  198 + assert(objects_max_container_size() == 13);
  199 + assert(objects_max_container_size_damaged() == 14);
  200 +
  201 + // Test parameter checking
  202 + QUtil::handle_result_code(qpdf_r_ok, "");
  203 + bool thrown = false;
  204 + try {
  205 + qpdf::global::handle_result(qpdf_r_success_mask);
  206 + } catch (std::logic_error const&) {
  207 + thrown = true;
  208 + }
  209 + assert(thrown);
  210 + thrown = false;
  211 + try {
  212 + qpdf::global::get_uint32(qpdf_param_e(42));
  213 + } catch (std::logic_error const&) {
  214 + thrown = true;
  215 + }
  216 + assert(thrown);
  217 + thrown = false;
  218 + try {
  219 + qpdf::global::set_uint32(qpdf_param_e(42), 42);
  220 + } catch (std::logic_error const&) {
  221 + thrown = true;
  222 + }
  223 + assert(thrown);
  224 +}
  225 +
156 226 void
157 227 runtest(int n, char const* filename1, char const* arg2)
158 228 {
... ... @@ -160,9 +230,7 @@ runtest(int n, char const* filename1, char const* arg2)
160 230 // the test suite to see how the test is invoked to find the file
161 231 // that the test is supposed to operate on.
162 232  
163   - std::set<int> ignore_filename = {
164   - 1,
165   - };
  233 + std::set<int> ignore_filename = {1, 2};
166 234  
167 235 QPDF pdf;
168 236 std::shared_ptr<char> file_buf;
... ... @@ -176,9 +244,7 @@ runtest(int n, char const* filename1, char const* arg2)
176 244 }
177 245  
178 246 std::map<int, void (*)(QPDF&, char const*)> test_functions = {
179   - {0, test_0},
180   - {1, test_1},
181   - };
  247 + {0, test_0}, {1, test_1}, {2, test_2}};
182 248  
183 249 auto fn = test_functions.find(n);
184 250 if (fn == test_functions.end()) {
... ...
libtests/qtest/objects.test
... ... @@ -11,7 +11,7 @@ require TestDriver;
11 11  
12 12 my $td = new TestDriver('objects');
13 13  
14   -my $n_tests = 2;
  14 +my $n_tests = 3;
15 15  
16 16 $td->runtest("integer type checks",
17 17 {$td->COMMAND => "objects 0 minimal.pdf"},
... ... @@ -23,4 +23,9 @@ $td-&gt;runtest(&quot;dictionary checks&quot;,
23 23 {$td->STRING => => "test 1 done\n", $td->EXIT_STATUS => 0},
24 24 $td->NORMALIZE_NEWLINES);
25 25  
  26 +$td->runtest("global object limits",
  27 + {$td->COMMAND => "objects 2 -"},
  28 + {$td->STRING => => "test 2 done\n", $td->EXIT_STATUS => 0},
  29 + $td->NORMALIZE_NEWLINES);
  30 +
26 31 $td->report($n_tests);
... ...