/src/qpdf/libqpdf/qpdf/Util.hh
Line | Count | Source |
1 | | #ifndef UTIL_HH |
2 | | #define UTIL_HH |
3 | | |
4 | | #include <qpdf/assert_debug.h> |
5 | | |
6 | | #include <concepts> |
7 | | #include <cstdint> |
8 | | #include <limits> |
9 | | #include <stdexcept> |
10 | | #include <string> |
11 | | #include <utility> |
12 | | |
13 | | using namespace std::literals; |
14 | | |
15 | | namespace qpdf::util |
16 | | { |
17 | | // qpdf::util is a collection of useful utility functions for qpdf internal use. It includes |
18 | | // inline functions, some of which are exposed as regular functions in QUtil. Implementations |
19 | | // are in QUtil.cc. |
20 | | |
21 | | // Throw a logic_error if 'cond' does not hold. |
22 | | // |
23 | | // DO NOT USE unless it is impractical or unnecessary to cover violations during CI Testing. |
24 | | template <typename T> |
25 | | inline void |
26 | | assertion(bool cond, T&& msg) |
27 | 42.2M | { |
28 | 42.2M | if (!cond) { |
29 | 0 | throw std::logic_error(std::forward<T>(msg)); |
30 | 0 | } |
31 | 42.2M | } void qpdf::util::assertion<char const (&) [44]>(bool, char const (&) [44]) Line | Count | Source | 27 | 131k | { | 28 | 131k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 131k | } |
Unexecuted instantiation: void qpdf::util::assertion<char const (&) [71]>(bool, char const (&) [71]) void qpdf::util::assertion<char const (&) [57]>(bool, char const (&) [57]) Line | Count | Source | 27 | 2.02k | { | 28 | 2.02k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 2.02k | } |
void qpdf::util::assertion<char const (&) [51]>(bool, char const (&) [51]) Line | Count | Source | 27 | 1.07k | { | 28 | 1.07k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 1.07k | } |
void qpdf::util::assertion<char const (&) [41]>(bool, char const (&) [41]) Line | Count | Source | 27 | 9.61k | { | 28 | 9.61k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 9.61k | } |
void qpdf::util::assertion<char const (&) [45]>(bool, char const (&) [45]) Line | Count | Source | 27 | 1.26M | { | 28 | 1.26M | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 1.26M | } |
void qpdf::util::assertion<char const (&) [121]>(bool, char const (&) [121]) Line | Count | Source | 27 | 595k | { | 28 | 595k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 595k | } |
Unexecuted instantiation: void qpdf::util::assertion<char const (&) [61]>(bool, char const (&) [61]) Unexecuted instantiation: void qpdf::util::assertion<char const (&) [74]>(bool, char const (&) [74]) Unexecuted instantiation: void qpdf::util::assertion<char const (&) [111]>(bool, char const (&) [111]) Unexecuted instantiation: void qpdf::util::assertion<char const (&) [106]>(bool, char const (&) [106]) Unexecuted instantiation: void qpdf::util::assertion<char const (&) [40]>(bool, char const (&) [40]) void qpdf::util::assertion<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(bool, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&) Line | Count | Source | 27 | 290k | { | 28 | 290k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 290k | } |
void qpdf::util::assertion<char const (&) [54]>(bool, char const (&) [54]) Line | Count | Source | 27 | 479k | { | 28 | 479k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 479k | } |
void qpdf::util::assertion<char const (&) [53]>(bool, char const (&) [53]) Line | Count | Source | 27 | 23.5k | { | 28 | 23.5k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 23.5k | } |
void qpdf::util::assertion<char const (&) [35]>(bool, char const (&) [35]) Line | Count | Source | 27 | 4.86k | { | 28 | 4.86k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 4.86k | } |
void qpdf::util::assertion<char const (&) [68]>(bool, char const (&) [68]) Line | Count | Source | 27 | 2.29k | { | 28 | 2.29k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 2.29k | } |
Unexecuted instantiation: void qpdf::util::assertion<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&>(bool, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) void qpdf::util::assertion<char const (&) [83]>(bool, char const (&) [83]) Line | Count | Source | 27 | 111k | { | 28 | 111k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 111k | } |
void qpdf::util::assertion<char const (&) [50]>(bool, char const (&) [50]) Line | Count | Source | 27 | 294k | { | 28 | 294k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 294k | } |
void qpdf::util::assertion<char const (&) [43]>(bool, char const (&) [43]) Line | Count | Source | 27 | 15.3k | { | 28 | 15.3k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 15.3k | } |
void qpdf::util::assertion<char const (&) [52]>(bool, char const (&) [52]) Line | Count | Source | 27 | 38.8M | { | 28 | 38.8M | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 38.8M | } |
void qpdf::util::assertion<char const (&) [58]>(bool, char const (&) [58]) Line | Count | Source | 27 | 1.62k | { | 28 | 1.62k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 1.62k | } |
void qpdf::util::assertion<char const (&) [48]>(bool, char const (&) [48]) Line | Count | Source | 27 | 16.4k | { | 28 | 16.4k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 16.4k | } |
void qpdf::util::assertion<char const (&) [46]>(bool, char const (&) [46]) Line | Count | Source | 27 | 10.0k | { | 28 | 10.0k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 10.0k | } |
Unexecuted instantiation: void qpdf::util::assertion<char const (&) [49]>(bool, char const (&) [49]) void qpdf::util::assertion<char const (&) [47]>(bool, char const (&) [47]) Line | Count | Source | 27 | 139k | { | 28 | 139k | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 139k | } |
void qpdf::util::assertion<char const (&) [56]>(bool, char const (&) [56]) Line | Count | Source | 27 | 749 | { | 28 | 749 | if (!cond) { | 29 | 0 | throw std::logic_error(std::forward<T>(msg)); | 30 | 0 | } | 31 | 749 | } |
|
32 | | |
33 | | template <typename T> |
34 | | inline void |
35 | | internal_error_if(bool cond, T&& msg) |
36 | 5.36M | { |
37 | 5.36M | if (cond) { |
38 | 0 | throw std::logic_error("INTERNAL ERROR: "s.append(std::forward<T>(msg)) |
39 | 0 | .append( |
40 | 0 | "\nThis is a qpdf bug. Please report at " |
41 | 0 | "https://github.com/qpdf/qpdf/issues")); |
42 | 0 | } |
43 | 5.36M | } void qpdf::util::internal_error_if<char const (&) [29]>(bool, char const (&) [29]) Line | Count | Source | 36 | 4.08M | { | 37 | 4.08M | if (cond) { | 38 | 0 | throw std::logic_error("INTERNAL ERROR: "s.append(std::forward<T>(msg)) | 39 | 0 | .append( | 40 | 0 | "\nThis is a qpdf bug. Please report at " | 41 | 0 | "https://github.com/qpdf/qpdf/issues")); | 42 | 0 | } | 43 | 4.08M | } |
void qpdf::util::internal_error_if<char const (&) [28]>(bool, char const (&) [28]) Line | Count | Source | 36 | 901k | { | 37 | 901k | if (cond) { | 38 | 0 | throw std::logic_error("INTERNAL ERROR: "s.append(std::forward<T>(msg)) | 39 | 0 | .append( | 40 | 0 | "\nThis is a qpdf bug. Please report at " | 41 | 0 | "https://github.com/qpdf/qpdf/issues")); | 42 | 0 | } | 43 | 901k | } |
void qpdf::util::internal_error_if<char const (&) [34]>(bool, char const (&) [34]) Line | Count | Source | 36 | 380k | { | 37 | 380k | if (cond) { | 38 | 0 | throw std::logic_error("INTERNAL ERROR: "s.append(std::forward<T>(msg)) | 39 | 0 | .append( | 40 | 0 | "\nThis is a qpdf bug. Please report at " | 41 | 0 | "https://github.com/qpdf/qpdf/issues")); | 42 | 0 | } | 43 | 380k | } |
Unexecuted instantiation: void qpdf::util::internal_error_if<char const (&) [44]>(bool, char const (&) [44]) |
44 | | |
45 | | template <typename T> |
46 | | inline void |
47 | | no_ci_rt_error_if(bool cond, T&& msg) |
48 | 4.27M | { |
49 | 4.27M | if (cond) { |
50 | 388 | throw std::runtime_error(std::forward<T>(msg)); |
51 | 388 | } |
52 | 4.27M | } Unexecuted instantiation: void qpdf::util::no_ci_rt_error_if<char const (&) [58]>(bool, char const (&) [58]) void qpdf::util::no_ci_rt_error_if<char const (&) [51]>(bool, char const (&) [51]) Line | Count | Source | 48 | 1.52M | { | 49 | 1.52M | if (cond) { | 50 | 18 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 18 | } | 52 | 1.52M | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [23]>(bool, char const (&) [23]) Line | Count | Source | 48 | 2.45M | { | 49 | 2.45M | if (cond) { | 50 | 243 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 243 | } | 52 | 2.45M | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [44]>(bool, char const (&) [44]) Line | Count | Source | 48 | 21.0k | { | 49 | 21.0k | if (cond) { | 50 | 37 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 37 | } | 52 | 21.0k | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [73]>(bool, char const (&) [73]) Line | Count | Source | 48 | 6.16k | { | 49 | 6.16k | if (cond) { | 50 | 0 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 0 | } | 52 | 6.16k | } |
void qpdf::util::no_ci_rt_error_if<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(bool, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&) Line | Count | Source | 48 | 41.1k | { | 49 | 41.1k | if (cond) { | 50 | 0 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 0 | } | 52 | 41.1k | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [69]>(bool, char const (&) [69]) Line | Count | Source | 48 | 18.0k | { | 49 | 18.0k | if (cond) { | 50 | 22 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 22 | } | 52 | 18.0k | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [59]>(bool, char const (&) [59]) Line | Count | Source | 48 | 167k | { | 49 | 167k | if (cond) { | 50 | 0 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 0 | } | 52 | 167k | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [42]>(bool, char const (&) [42]) Line | Count | Source | 48 | 20.6k | { | 49 | 20.6k | if (cond) { | 50 | 0 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 0 | } | 52 | 20.6k | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [49]>(bool, char const (&) [49]) Line | Count | Source | 48 | 2.36k | { | 49 | 2.36k | if (cond) { | 50 | 11 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 11 | } | 52 | 2.36k | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [88]>(bool, char const (&) [88]) Line | Count | Source | 48 | 1.60k | { | 49 | 1.60k | if (cond) { | 50 | 0 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 0 | } | 52 | 1.60k | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [45]>(bool, char const (&) [45]) Line | Count | Source | 48 | 1.60k | { | 49 | 1.60k | if (cond) { | 50 | 3 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 3 | } | 52 | 1.60k | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [32]>(bool, char const (&) [32]) Line | Count | Source | 48 | 1.60k | { | 49 | 1.60k | if (cond) { | 50 | 6 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 6 | } | 52 | 1.60k | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [35]>(bool, char const (&) [35]) Line | Count | Source | 48 | 13.6k | { | 49 | 13.6k | if (cond) { | 50 | 12 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 12 | } | 52 | 13.6k | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [53]>(bool, char const (&) [53]) Line | Count | Source | 48 | 749 | { | 49 | 749 | if (cond) { | 50 | 12 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 12 | } | 52 | 749 | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [92]>(bool, char const (&) [92]) Line | Count | Source | 48 | 733 | { | 49 | 733 | if (cond) { | 50 | 0 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 0 | } | 52 | 733 | } |
void qpdf::util::no_ci_rt_error_if<char const (&) [36]>(bool, char const (&) [36]) Line | Count | Source | 48 | 730 | { | 49 | 730 | if (cond) { | 50 | 24 | throw std::runtime_error(std::forward<T>(msg)); | 51 | 24 | } | 52 | 730 | } |
|
53 | | |
54 | | /// @brief Return true if `val` fits in `T` (predicate only). |
55 | | /// |
56 | | /// @tparam T integral target type |
57 | | /// @param val value to test |
58 | | /// @return true if `val` fits in `T` |
59 | | template <typename T> |
60 | | requires std::integral<T> |
61 | | bool |
62 | | fits(std::integral auto val) |
63 | 151k | { |
64 | | if constexpr (std::cmp_less( |
65 | | std::numeric_limits<decltype(val)>::min(), |
66 | 48.8k | std::numeric_limits<T>::min())) { |
67 | 48.8k | if (std::cmp_less(val, std::numeric_limits<T>::min())) { |
68 | 0 | return false; |
69 | 0 | } |
70 | 48.8k | } |
71 | | if constexpr (std::cmp_greater( |
72 | | std::numeric_limits<decltype(val)>::max(), |
73 | 126k | std::numeric_limits<T>::max())) { |
74 | 126k | if (std::cmp_greater(val, std::numeric_limits<T>::max())) { |
75 | 6 | return false; |
76 | 6 | } |
77 | 126k | } |
78 | 126k | return true; |
79 | 151k | } _ZN4qpdf4util4fitsIjTkNSt3__18integralElQsr3stdE8integralIT_EEEbT0_ Line | Count | Source | 63 | 24.4k | { | 64 | | if constexpr (std::cmp_less( | 65 | | std::numeric_limits<decltype(val)>::min(), | 66 | 24.4k | std::numeric_limits<T>::min())) { | 67 | 24.4k | if (std::cmp_less(val, std::numeric_limits<T>::min())) { | 68 | 0 | return false; | 69 | 0 | } | 70 | 24.4k | } | 71 | | if constexpr (std::cmp_greater( | 72 | | std::numeric_limits<decltype(val)>::max(), | 73 | 24.4k | std::numeric_limits<T>::max())) { | 74 | 24.4k | if (std::cmp_greater(val, std::numeric_limits<T>::max())) { | 75 | 0 | return false; | 76 | 0 | } | 77 | 24.4k | } | 78 | 24.4k | return true; | 79 | 24.4k | } |
_ZN4qpdf4util4fitsIjTkNSt3__18integralEiQsr3stdE8integralIT_EEEbT0_ Line | Count | Source | 63 | 24.4k | { | 64 | | if constexpr (std::cmp_less( | 65 | | std::numeric_limits<decltype(val)>::min(), | 66 | 24.4k | std::numeric_limits<T>::min())) { | 67 | 24.4k | if (std::cmp_less(val, std::numeric_limits<T>::min())) { | 68 | 0 | return false; | 69 | 0 | } | 70 | 24.4k | } | 71 | | if constexpr (std::cmp_greater( | 72 | | std::numeric_limits<decltype(val)>::max(), | 73 | | std::numeric_limits<T>::max())) { | 74 | | if (std::cmp_greater(val, std::numeric_limits<T>::max())) { | 75 | | return false; | 76 | | } | 77 | | } | 78 | 24.4k | return true; | 79 | 24.4k | } |
_ZN4qpdf4util4fitsIjTkNSt3__18integralEyQsr3stdE8integralIT_EEEbT0_ Line | Count | Source | 63 | 102k | { | 64 | | if constexpr (std::cmp_less( | 65 | | std::numeric_limits<decltype(val)>::min(), | 66 | | std::numeric_limits<T>::min())) { | 67 | | if (std::cmp_less(val, std::numeric_limits<T>::min())) { | 68 | | return false; | 69 | | } | 70 | | } | 71 | | if constexpr (std::cmp_greater( | 72 | | std::numeric_limits<decltype(val)>::max(), | 73 | 102k | std::numeric_limits<T>::max())) { | 74 | 102k | if (std::cmp_greater(val, std::numeric_limits<T>::max())) { | 75 | 6 | return false; | 76 | 6 | } | 77 | 102k | } | 78 | 102k | return true; | 79 | 102k | } |
Unexecuted instantiation: _ZN4qpdf4util4fitsIlTkNSt3__18integralEjQsr3stdE8integralIT_EEEbT0_ Unexecuted instantiation: _ZN4qpdf4util4fitsIiTkNSt3__18integralEjQsr3stdE8integralIT_EEEbT0_ |
80 | | |
81 | | /// @brief Convert `val` to `T`; throws std::range_error if out-of-range. |
82 | | /// |
83 | | /// @tparam T integral target type |
84 | | /// @param val value to convert |
85 | | /// @return Converted value as `T` |
86 | | template <typename T> |
87 | | requires std::integral<T> |
88 | | T |
89 | | to(std::integral auto val) |
90 | | { |
91 | | if (!fits<T>(val)) { |
92 | | throw std::range_error("out of range converting integral values"); |
93 | | } |
94 | | return static_cast<T>(val); |
95 | | } |
96 | | |
97 | | inline constexpr char |
98 | | hex_decode_char(char digit) |
99 | 839k | { |
100 | 839k | return digit <= '9' && digit >= '0' |
101 | 839k | ? char(digit - '0') |
102 | 839k | : (digit >= 'a' ? char(digit - 'a' + 10) |
103 | 563k | : (digit >= 'A' ? char(digit - 'A' + 10) : '\20')); |
104 | 839k | } |
105 | | |
106 | | inline constexpr bool |
107 | | is_hex_digit(char ch) |
108 | 0 | { |
109 | 0 | return hex_decode_char(ch) < '\20'; |
110 | 0 | } |
111 | | |
112 | | inline constexpr bool |
113 | | is_space(char ch) |
114 | 47.6M | { |
115 | 47.6M | return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\v'; |
116 | 47.6M | } |
117 | | |
118 | | inline bool |
119 | | is_digit(char ch) |
120 | 20.9M | { |
121 | 20.9M | return (ch >= '0' && ch <= '9'); |
122 | 20.9M | } |
123 | | |
124 | | // Returns lower-case hex-encoded version of the char including a leading "#". |
125 | | inline std::string |
126 | | hex_encode_char(char c) |
127 | 2.27M | { |
128 | 2.27M | static auto constexpr hexchars = "0123456789abcdef"; |
129 | 2.27M | return {'#', hexchars[static_cast<unsigned char>(c) >> 4], hexchars[c & 0x0f]}; |
130 | 2.27M | } |
131 | | |
132 | | // Numerically increment a digit string. Ignore the last 'tail' characters. |
133 | | inline void |
134 | | increment(std::string& s, int tail = 0) |
135 | 43.6k | { |
136 | 43.6k | auto end = s.rend(); |
137 | 48.2k | for (auto it = s.rbegin() + tail; it != end; ++it) { |
138 | 47.8k | ++*it; |
139 | 47.8k | if (*it != ':') { |
140 | 43.2k | return; |
141 | 43.2k | } |
142 | 4.60k | *it = '0'; |
143 | 4.60k | } |
144 | 446 | s.insert(0, 1, '1'); |
145 | 446 | } |
146 | | |
147 | | inline bool |
148 | | is_utf16(std::string const& str) |
149 | 0 | { |
150 | 0 | return str.starts_with("\xfe\xff") || str.starts_with("\xff\xfe"); |
151 | 0 | } |
152 | | |
153 | | inline bool |
154 | | is_explicit_utf8(std::string const& str) |
155 | 0 | { |
156 | | // QPDF_String.cc knows that this is a 3-byte sequence. |
157 | 0 | return str.starts_with("\xef\xbb\xbf"); |
158 | 0 | } |
159 | | |
160 | | std::string random_string(size_t len); |
161 | | |
162 | | // Test helpers |
163 | | |
164 | | /// @brief Predicate: returns true if invoking `f()` throws an exception of type `E`. |
165 | | /// |
166 | | /// Internal test helper used by unit tests: call `throws<SomeException>([](){ ... })` and |
167 | | /// it returns true when the callable throws `SomeException` and false otherwise. |
168 | | /// The callable must be invocable with no arguments. |
169 | | template <typename E, typename F> |
170 | | requires std::invocable<F> |
171 | | inline bool |
172 | | throws(F&& f) |
173 | | { |
174 | | try { |
175 | | std::forward<F>(f)(); |
176 | | return false; |
177 | | } catch (E const&) { |
178 | | return true; |
179 | | } catch (...) { |
180 | | return false; |
181 | | } |
182 | | } |
183 | | |
184 | | } // namespace qpdf::util |
185 | | |
186 | | #endif // UTIL_HH |