// Copyright (c) 2005-2021 Jay Berkenbilt
// Copyright (c) 2022-2026 Jay Berkenbilt and Manfred Holger
//
// This file is part of qpdf.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under
// the License.
//
// Versions of qpdf prior to version 7 were released under the terms of version 2.0 of the Artistic
// License. At your option, you may continue to consider qpdf to be licensed under those terms.
// Please see the manual for additional information.

#ifndef GLOBAL_HH
#define GLOBAL_HH

#include <qpdf/Constants.h>

#include <qpdf/QUtil.hh>
#include <qpdf/qpdf-c.h>

#include <cstdint>

namespace qpdf::global
{
    /// Helper function to translate result codes into C++ exceptions - for qpdf internal use only.
    inline void
    handle_result(qpdf_result_e result)
    {
        if (result != qpdf_r_ok) {
            QUtil::handle_result_code(result, "qpdf::global");
        }
    }

    /// Helper function to wrap calls to qpdf_global_get_uint32 - for qpdf internal use only.
    inline uint32_t
    get_uint32(qpdf_param_e param)
    {
        uint32_t value;
        handle_result(qpdf_global_get_uint32(param, &value));
        return value;
    }

    /// Helper function to wrap calls to qpdf_global_set_uint32 - for qpdf internal use only.
    inline void
    set_uint32(qpdf_param_e param, uint32_t value)
    {
        handle_result(qpdf_global_set_uint32(param, value));
    }

    /// @brief Retrieves the number of limit errors.
    ///
    /// Returns the number of times a global limit was exceeded. This item is read only.
    ///
    /// @return The number of limit errors.
    ///
    /// @since 12.3
    inline uint32_t
    limit_errors()
    {
        return get_uint32(qpdf_p_limit_errors);
    }

    namespace options
    {
        /// @brief  Retrieves whether inspection mode is set.
        ///
        /// @return True if inspection mode is set.
        ///
        /// @since 12.3
        inline bool
        inspection_mode()
        {
            return get_uint32(qpdf_p_inspection_mode) != 0;
        }

        /// @brief  Set inspection mode if `true` is passed.
        ///
        /// This function enables restrictive inspection mode if `true` is passed. Inspection mode
        /// must be enabled before a QPDF object is created. By default inspection mode is off.
        /// Calling `inspection_mode(false)` is not supported and currently is a no-op.
        ///
        /// @param value A boolean indicating whether to enable (true) inspection mode.
        ///
        /// @since 12.3
        inline void
        inspection_mode(bool value)
        {
            set_uint32(qpdf_p_inspection_mode, value ? QPDF_TRUE : QPDF_FALSE);
        }

        /// @brief  Retrieves whether fuzz mode is set.
        ///
        /// Fuzz mode is intended for use when building fuzzers and sets various global limits with
        /// the aim of avoiding spurious time-outs and out-of-memory errors as well as limiting the
        /// time spent fuzzing qpdf's dependencies instead of fuzzing qpdf itself. These limits
        /// cannot be imposed on qpdf during normal operation since legitimate PDF files can be very
        /// large and complex and as result may require more memory and longer runtimes than is
        /// allowed during fuzzing. By default fuzz mode is off.
        ///
        /// @return True if fuzz mode is set.
        ///
        /// @since 12.4
        inline bool
        fuzz_mode()
        {
            return get_uint32(qpdf_p_fuzz_mode) != 0;
        }

        /// @brief  Set fuzz mode if `true` is passed.
        ///
        /// This function enables fuzz mode if `true` is passed. Fuzz mode is intended for use when
        /// building fuzzers and sets various global limits with the aim of avoiding spurious
        /// time-outs and out-of-memory errors as well as limiting the time spent fuzzing qpdf's
        /// dependencies instead of fuzzing qpdf itself. These limits cannot be imposed on qpdf
        /// during normal operation since legitimate PDF files can be very large and complex and as
        /// result may require more memory and longer runtimes than is allowed during fuzzing. By
        /// default fuzz mode is off. Calling `fuzz_mode(false)` is not supported and currently is a
        /// no-op.
        ///
        /// @param value A boolean indicating whether to enable (true) fuzz mode.
        ///
        /// @since 12.4
        inline void
        fuzz_mode(bool value)
        {
            set_uint32(qpdf_p_fuzz_mode, value ? QPDF_TRUE : QPDF_FALSE);
        }

        /// @brief  Retrieves whether DCT throw-on-corrupt-data option is set.
        ///
        /// When enabled, DCT decompression will treat corrupt data as an error and throw an
        /// exception. By default this option is enabled.
        ///
        /// @return True if DCT throw-on-corrupt-data is set.
        ///
        /// @since 12.4
        inline bool
        dct_throw_on_corrupt_data()
        {
            return get_uint32(qpdf_p_dct_throw_on_corrupt_data) != 0;
        }

        /// @brief  Set the DCT throw-on-corrupt-data option.
        ///
        /// When enabled, DCT decompression will treat corrupt data as an error and throw an
        /// exception. Passing `false` will cause the decompressor to attempt to continue on
        /// corrupt JPEG data where possible.
        ///
        /// @param value A boolean indicating whether to enable (true) or disable (false) the
        ///              behavior.
        ///
        /// @since 12.4
        inline void
        dct_throw_on_corrupt_data(bool value)
        {
            set_uint32(qpdf_p_dct_throw_on_corrupt_data, value ? QPDF_TRUE : QPDF_FALSE);
        }

        /// @brief  Retrieves whether default limits are enabled.
        ///
        /// @return True if default limits are enabled.
        ///
        /// @since 12.3
        inline bool
        default_limits()
        {
            return get_uint32(qpdf_p_default_limits) != 0;
        }

        /// @brief  Disable all optional default limits if `false` is passed.
        ///
        /// This function disables all optional default limits if `false` is passed. Once default
        /// values have been disabled they cannot be re-enabled. Passing `true` has no effect. This
        /// function will leave any limits that have been explicitly set unchanged. Some limits,
        /// such as limits imposed to avoid stack overflows, cannot be disabled but can be changed.
        ///
        /// @param value A boolean indicating whether to disable (false) the default limits.
        ///
        /// @since 12.3
        inline void
        default_limits(bool value)
        {
            set_uint32(qpdf_p_default_limits, value ? QPDF_TRUE : QPDF_FALSE);
        }

    } // namespace options

    namespace limits
    {
        /// @brief Retrieves the default maximum number of warnings accepted per document.
        ///
        /// This value provides a default for `QPDF::setMaxWarnings`. A value of 0 indicates no
        /// limit. The default is 0.
        ///
        /// @return The configured default maximum warnings per document.
        ///
        /// @since 12.4
        inline uint32_t
        doc_max_warnings()
        {
            return get_uint32(qpdf_p_doc_max_warnings);
        }

        /// @brief Sets the default maximum number of warnings accepted per document.
        ///
        /// This value is used as the default in newly-created `QPDF` objects as the initial
        /// setting for `QPDF::setMaxWarnings`.
        ///
        /// @param val The maximum warnings per document to set. A value of 0 disables the limit.
        ///
        /// @since 12.4
        inline void
        doc_max_warnings(uint32_t val)
        {
            set_uint32(qpdf_p_doc_max_warnings, val);
        }

        /// @brief Retrieves the maximum nesting level while parsing objects.
        ///
        /// @return The maximum nesting level while parsing objects.
        ///
        /// @note The maximum nesting level cannot be disabled by calling `default_limits(false)`.
        ///
        /// @since 12.3
        inline uint32_t
        parser_max_nesting()
        {
            return get_uint32(qpdf_p_parser_max_nesting);
        }

        /// @brief Sets the maximum nesting level while parsing objects.
        ///
        /// @param value The maximum nesting level to set.
        ///
        /// @note The maximum nesting level cannot be disabled by calling `default_limits(false)`.
        ///
        /// @since 12.3
        inline void
        parser_max_nesting(uint32_t value)
        {
            set_uint32(qpdf_p_parser_max_nesting, value);
        }

        /// @brief Retrieves the maximum number of errors allowed while parsing objects.
        ///
        /// A value of 0 means that there is no maximum imposed.
        ///
        /// @return The maximum number of errors allowed while parsing objects.
        ///
        /// @since 12.3
        inline uint32_t
        parser_max_errors()
        {
            return get_uint32(qpdf_p_parser_max_errors);
        }

        /// Sets the maximum number of errors allowed while parsing objects.
        ///
        /// A value of 0 means that there is no maximum imposed.
        ///
        /// @param value The maximum number of errors allowed while parsing objects to set.
        ///
        /// @since 12.3
        inline void
        parser_max_errors(uint32_t value)
        {
            set_uint32(qpdf_p_parser_max_errors, value);
        }

        /// @brief Retrieves the maximum number of top-level objects allowed in a container while
        ///        parsing.
        ///
        /// The limit applies when the PDF document's xref table is undamaged and the object itself
        /// can be parsed without errors. The default limit is 4,294,967,295.
        ///
        /// @return The maximum number of top-level objects allowed in a container while parsing
        ///         objects.
        ///
        /// @since 12.3
        inline uint32_t
        parser_max_container_size()
        {
            return get_uint32(qpdf_p_parser_max_container_size);
        }

        /// @brief Sets the maximum number of top-level objects allowed in a container while
        ///        parsing.
        ///
        /// The limit applies when the PDF document's xref table is undamaged and the object itself
        /// can be parsed without errors. The default limit is 4,294,967,295.
        ///
        /// @param value  The maximum number of top-level objects allowed in a container while
        ///               parsing objects to set.
        ///
        /// @since 12.3
        inline void
        parser_max_container_size(uint32_t value)
        {
            set_uint32(qpdf_p_parser_max_container_size, value);
        }

        /// @brief Retrieves the maximum number of top-level objects allowed in a container while
        ///        parsing objects.
        ///
        /// The limit applies when the PDF document's xref table is damaged or the object itself is
        /// damaged. The limit also applies when parsing xref streams. The default limit is 5,000.
        ///
        /// @return The maximum number of top-level objects allowed in a container while parsing
        ///         objects.
        ///
        /// @since 12.3
        inline uint32_t
        parser_max_container_size_damaged()
        {
            return get_uint32(qpdf_p_parser_max_container_size_damaged);
        }

        /// @brief Sets the maximum number of top-level objects allowed in a container while
        ///        parsing.
        ///
        /// The limit applies when the PDF document's xref table is damaged or the object itself is
        /// damaged. The limit also applies when parsing trailer dictionaries and xref streams. The
        /// default limit is 5,000.
        ///
        /// @param value  The maximum number of top-level objects allowed in a container while
        ///               parsing objects to set.
        ///
        /// @since 12.3
        inline void
        parser_max_container_size_damaged(uint32_t value)
        {
            set_uint32(qpdf_p_parser_max_container_size_damaged, value);
        }

        /// @brief Retrieves the maximum number of filters allowed when filtering streams.
        ///
        /// An excessive number of stream filters is usually a sign that a file is damaged or
        /// specially constructed. If the maximum is exceeded for a stream the stream is treated as
        /// unfilterable. The default maximum is 25.
        ///
        /// @return The maximum number of filters allowed when filtering streams.
        ///
        /// @since 12.3
        inline uint32_t
        max_stream_filters()
        {
            return get_uint32(qpdf_p_max_stream_filters);
        }

        /// @brief Sets the maximum number of filters allowed when filtering streams.
        ///
        /// An excessive number of stream filters is usually a sign that a file is damaged or
        /// specially constructed. If the maximum is exceeded for a stream the stream is treated as
        /// unfilterable. The default maximum is 25.
        ///
        /// @param value  The maximum number of filters allowed when filtering streams to set.
        ///
        /// @since 12.3
        inline void
        max_stream_filters(uint32_t value)
        {
            set_uint32(qpdf_p_max_stream_filters, value);
        }

        /// @brief  Retrieves the maximum amount of memory in bytes allowed for DCT (JPEG)
        ///         decompression.
        ///
        /// Streams requiring memory in excess of the limit for decompression are treated as
        /// unfilterable. A value of 0 indicates no limit. The default is 0.
        ///
        /// @return The configured maximum memory in bytes for DCT decompression.
        ///
        /// @since 12.4
        inline uint32_t
        dct_max_memory()
        {
            return get_uint32(qpdf_p_dct_max_memory);
        }

        /// @brief  Sets the maximum amount of memory in bytes allowed for DCT (JPEG) decompression.
        ///
        /// Streams requiring memory in excess of the limit for decompression are treated as
        /// unfilterable. A value of 0 indicates no limit. The default is 0.
        ///
        /// @param val The maximum memory in bytes to allow for DCT decompression.
        ///
        /// @since 12.4
        inline void
        dct_max_memory(uint32_t val)
        {
            set_uint32(qpdf_p_dct_max_memory, val);
        }

        /// @brief  Retrieves the maximum number of progressive scans allowed for DCT (JPEG)
        ///         decompression.
        ///
        /// Streams exceeding the limit are treated as unfilterable. A value of 0 indicates no
        /// limit. The default is 0.
        ///
        /// @return The configured maximum progressive scans for DCT decompression.
        ///
        /// @since 12.4
        inline uint32_t
        dct_max_progressive_scans()
        {
            return get_uint32(qpdf_p_dct_max_progressive_scans);
        }

        /// @brief  Sets the maximum number of progressive scans allowed for DCT (JPEG)
        ///         decompression.
        ///
        /// Streams exceeding the limit are treated as unfilterable. A value of 0 indicates no
        /// limit. The default is 0.
        ///
        /// @param val The maximum progressive scans to allow for DCT operations.
        ///
        /// @since 12.4
        inline void
        dct_max_progressive_scans(uint32_t val)
        {
            set_uint32(qpdf_p_dct_max_progressive_scans, val);
        }

        /// @brief  Retrieves the maximum amount of memory in bytes allowed for Flate (zlib)
        ///         decompression/processing.
        ///
        /// Streams requiring memory in excess of the limit for Flate processing are treated as
        /// unfilterable. A value of 0 indicates no limit. The default is 0.
        ///
        /// @return The configured maximum memory in bytes for Flate processing.
        ///
        /// @since 12.4
        inline uint32_t
        flate_max_memory()
        {
            return get_uint32(qpdf_p_flate_max_memory);
        }

        /// @brief  Sets the maximum amount of memory in bytes allowed for Flate (zlib)
        ///         decompression/processing.
        ///
        /// Streams requiring memory in excess of the limit for processing are treated as
        /// unfilterable. A value of 0 indicates no limit. The default is 0.
        ///
        /// @param val The maximum memory in bytes to allow for Flate processing.
        ///
        /// @since 12.4
        inline void
        flate_max_memory(uint32_t val)
        {
            set_uint32(qpdf_p_flate_max_memory, val);
        }

        /// @brief  Retrieves the maximum amount of memory in bytes allowed for PNG filter
        ///         processing.
        ///
        /// Streams requiring memory in excess of the limit are treated as unfilterable. A value of
        /// 0 indicates no limit. The default is 0.
        ///
        /// @return The configured maximum memory in bytes for PNG processing.
        ///
        /// @since 12.4
        inline uint32_t
        png_max_memory()
        {
            return get_uint32(qpdf_p_png_max_memory);
        }

        /// @brief  Sets the maximum amount of memory in bytes allowed for PNG filter processing.
        ///
        /// Streams requiring memory in excess of the limit are treated as unfilterable. A value of
        /// 0 indicates no limit. The default is 0.
        ///
        /// @param val The maximum memory in bytes to allow for PNG processing.
        ///
        /// @since 12.4
        inline void
        png_max_memory(uint32_t val)
        {
            set_uint32(qpdf_p_png_max_memory, val);
        }

        /// @brief  Retrieves the maximum amount of memory in bytes allowed for RunLength
        ///         decoding/processing.
        ///
        /// Streams requiring memory in excess of the limit for run-length processing are treated
        /// as unfilterable. A value of 0 indicates no limit. The default is 0.
        ///
        /// @return The configured maximum memory in bytes for run-length processing.
        ///
        /// @since 12.4
        inline uint32_t
        run_length_max_memory()
        {
            return get_uint32(qpdf_p_run_length_max_memory);
        }

        /// @brief  Sets the maximum amount of memory in bytes allowed for RunLength
        ///         decoding/processing.
        ///
        /// Streams requiring memory in excess of the limit for processing are treated as
        /// unfilterable. A value of 0 indicates no limit. The default is 0.
        ///
        /// @param val The maximum memory in bytes to allow for run-length processing.
        ///
        /// @since 12.4
        inline void
        run_length_max_memory(uint32_t val)
        {
            set_uint32(qpdf_p_run_length_max_memory, val);
        }

        /// @brief  Retrieves the maximum amount of memory in bytes allowed for TIFF processing.
        ///
        /// Streams requiring memory in excess of the limit for TIFF processing are treated as
        /// unfilterable. A value of 0 indicates no limit. The default is 0.
        ///
        /// @return The configured maximum memory in bytes for TIFF processing.
        ///
        /// @since 12.4
        inline uint32_t
        tiff_max_memory()
        {
            return get_uint32(qpdf_p_tiff_max_memory);
        }

        /// @brief  Sets the maximum amount of memory in bytes allowed for TIFF processing.
        ///
        /// Streams requiring memory in excess of the limit for processing are treated as
        /// unfilterable. A value of 0 indicates no limit. The default is 0.
        ///
        /// @param val The maximum memory in bytes to allow for TIFF processing.
        ///
        /// @since 12.4
        inline void
        tiff_max_memory(uint32_t val)
        {
            set_uint32(qpdf_p_tiff_max_memory, val);
        }

    } // namespace limits

} // namespace qpdf::global

#endif // GLOBAL_HH
