Commit 16cb3ca5c55c3288ffec8e4b641f3531d4da7afd

Authored by m-holger
1 parent 9e8bd681

Refactor error handling across codebase with `util::assertion` and `util::no_ci_rt_error_if`.

- Standardize error handling by replacing repetitive throw statements with helper functions.
- Add test coverage for new helper functions in error handling.
- Enhance maintainability and readability with concise utilities.
libqpdf/NNTree.cc
@@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
9 #include <qpdf/QPDF_private.hh> 9 #include <qpdf/QPDF_private.hh>
10 #include <qpdf/QTC.hh> 10 #include <qpdf/QTC.hh>
11 #include <qpdf/QUtil.hh> 11 #include <qpdf/QUtil.hh>
  12 +#include <qpdf/Util.hh>
12 13
13 #include <bit> 14 #include <bit>
14 #include <exception> 15 #include <exception>
@@ -65,10 +66,8 @@ NNTreeIterator::updateIValue(bool allow_invalid) @@ -65,10 +66,8 @@ NNTreeIterator::updateIValue(bool allow_invalid)
65 } 66 }
66 67
67 if (item_number < 0 || !node) { 68 if (item_number < 0 || !node) {
68 - if (!allow_invalid) {  
69 - throw std::logic_error(  
70 - "attempt made to dereference an invalid name/number tree iterator");  
71 - } 69 + util::assertion(
  70 + allow_invalid, "attempt made to dereference an invalid name/number tree iterator");
72 return; 71 return;
73 } 72 }
74 impl.error(node, "update ivalue: items array is too short"); 73 impl.error(node, "update ivalue: items array is too short");
@@ -210,9 +209,7 @@ NNTreeIterator::split(Dictionary to_split, std::list&lt;PathElement&gt;::iterator pare @@ -210,9 +209,7 @@ NNTreeIterator::split(Dictionary to_split, std::list&lt;PathElement&gt;::iterator pare
210 // node: A 209 // node: A
211 // item_number: 0 210 // item_number: 0
212 211
213 - if (!valid()) {  
214 - throw std::logic_error("NNTreeIterator::split called an invalid iterator");  
215 - } 212 + util::assertion(valid(), "NNTreeIterator::split called an invalid iterator");
216 213
217 // Find the array we actually need to split, which is either this node's kids or items. 214 // Find the array we actually need to split, which is either this node's kids or items.
218 Array kids = to_split["/Kids"]; 215 Array kids = to_split["/Kids"];
@@ -228,13 +225,12 @@ NNTreeIterator::split(Dictionary to_split, std::list&lt;PathElement&gt;::iterator pare @@ -228,13 +225,12 @@ NNTreeIterator::split(Dictionary to_split, std::list&lt;PathElement&gt;::iterator pare
228 first_half = kids; 225 first_half = kids;
229 n = nkids; 226 n = nkids;
230 key = "/Kids"; 227 key = "/Kids";
231 - } else if (nitems > 0) { 228 + } else {
  229 + util::assertion(nitems > 0, "NNTreeIterator::split called on invalid node");
232 first_half = items; 230 first_half = items;
233 n = nitems; 231 n = nitems;
234 threshold *= 2; 232 threshold *= 2;
235 key = impl.itemsKey(); 233 key = impl.itemsKey();
236 - } else {  
237 - throw std::logic_error("NNTreeIterator::split called on invalid node");  
238 } 234 }
239 235
240 if (n <= threshold) { 236 if (n <= threshold) {
@@ -369,9 +365,7 @@ NNTreeIterator::remove() @@ -369,9 +365,7 @@ NNTreeIterator::remove()
369 { 365 {
370 // Remove this item, leaving the tree valid and this iterator pointing to the next item. 366 // Remove this item, leaving the tree valid and this iterator pointing to the next item.
371 367
372 - if (!valid()) {  
373 - throw std::logic_error("attempt made to remove an invalid iterator");  
374 - } 368 + util::assertion(valid(), "attempt made to remove an invalid iterator");
375 Array items = node[impl.itemsKey()]; 369 Array items = node[impl.itemsKey()];
376 int nitems = static_cast<int>(items.size()); 370 int nitems = static_cast<int>(items.size());
377 if (std::cmp_greater(item_number + 2, nitems)) { 371 if (std::cmp_greater(item_number + 2, nitems)) {
@@ -396,13 +390,12 @@ NNTreeIterator::remove() @@ -396,13 +390,12 @@ NNTreeIterator::remove()
396 // the previous item. 390 // the previous item.
397 item_number -= 2; 391 item_number -= 2;
398 increment(false); 392 increment(false);
399 - } else if (item_number < nitems) { 393 + } else {
  394 + util::assertion(
  395 + item_number < nitems, "NNTreeIterator::remove: item_number > nitems after erase");
400 // We don't have to do anything since the removed item's successor now occupies its 396 // We don't have to do anything since the removed item's successor now occupies its
401 // former location. 397 // former location.
402 updateIValue(); 398 updateIValue();
403 - } else {  
404 - // We already checked to ensure this condition would not happen.  
405 - throw std::logic_error("NNTreeIterator::remove: item_number > nitems after erase");  
406 } 399 }
407 return; 400 return;
408 } 401 }
libqpdf/Pl_AES_PDF.cc
@@ -3,10 +3,13 @@ @@ -3,10 +3,13 @@
3 #include <qpdf/QIntC.hh> 3 #include <qpdf/QIntC.hh>
4 #include <qpdf/QPDFCryptoProvider.hh> 4 #include <qpdf/QPDFCryptoProvider.hh>
5 #include <qpdf/QUtil.hh> 5 #include <qpdf/QUtil.hh>
  6 +#include <qpdf/Util.hh>
  7 +
6 #include <cstring> 8 #include <cstring>
7 -#include <stdexcept>  
8 #include <string> 9 #include <string>
9 10
  11 +using namespace qpdf;
  12 +
10 bool Pl_AES_PDF::use_static_iv = false; 13 bool Pl_AES_PDF::use_static_iv = false;
11 14
12 Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, bool encrypt, std::string key) : 15 Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, bool encrypt, std::string key) :
@@ -15,12 +18,8 @@ Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, bool encrypt, std @@ -15,12 +18,8 @@ Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, bool encrypt, std
15 crypto(QPDFCryptoProvider::getImpl()), 18 crypto(QPDFCryptoProvider::getImpl()),
16 encrypt(encrypt) 19 encrypt(encrypt)
17 { 20 {
18 - if (!next) {  
19 - throw std::logic_error("Attempt to create Pl_AES_PDF with nullptr as next");  
20 - }  
21 - if (!(key.size() == 32 || key.size() == 16)) {  
22 - throw std::runtime_error("unsupported key length");  
23 - } 21 + util::assertion(next, "Attempt to create Pl_AES_PDF with nullptr as next");
  22 + util::no_ci_rt_error_if(!(key.size() == 32 || key.size() == 16), "unsupported key length");
24 std::memset(this->inbuf, 0, this->buf_size); 23 std::memset(this->inbuf, 0, this->buf_size);
25 std::memset(this->outbuf, 0, this->buf_size); 24 std::memset(this->outbuf, 0, this->buf_size);
26 std::memset(this->cbc_block, 0, this->buf_size); 25 std::memset(this->cbc_block, 0, this->buf_size);
@@ -41,12 +40,10 @@ Pl_AES_PDF::disablePadding() @@ -41,12 +40,10 @@ Pl_AES_PDF::disablePadding()
41 void 40 void
42 Pl_AES_PDF::setIV(unsigned char const* iv, size_t bytes) 41 Pl_AES_PDF::setIV(unsigned char const* iv, size_t bytes)
43 { 42 {
44 - if (bytes != buf_size) {  
45 - throw std::logic_error(  
46 - "Pl_AES_PDF: specified initialization vector"  
47 - " size in bytes must be " + 43 + util::assertion(
  44 + bytes == buf_size,
  45 + "Pl_AES_PDF: specified initialization vector size in bytes must be " +
48 std::to_string(bytes)); 46 std::to_string(bytes));
49 - }  
50 use_specified_iv = true; 47 use_specified_iv = true;
51 memcpy(specified_iv, iv, bytes); 48 memcpy(specified_iv, iv, bytes);
52 } 49 }
@@ -103,9 +100,7 @@ Pl_AES_PDF::finish() @@ -103,9 +100,7 @@ Pl_AES_PDF::finish()
103 // This is never supposed to happen as the output is always supposed to be padded. 100 // This is never supposed to happen as the output is always supposed to be padded.
104 // However, we have encountered files for which the output is not a multiple of the 101 // However, we have encountered files for which the output is not a multiple of the
105 // block size. In this case, pad with zeroes and hope for the best. 102 // block size. In this case, pad with zeroes and hope for the best.
106 - if (offset >= buf_size) {  
107 - throw std::logic_error("buffer overflow in AES encryption pipeline");  
108 - } 103 + util::assertion(offset < buf_size, "buffer overflow in AES encryption pipeline");
109 std::memset(inbuf + offset, 0, buf_size - offset); 104 std::memset(inbuf + offset, 0, buf_size - offset);
110 offset = buf_size; 105 offset = buf_size;
111 } 106 }
@@ -136,9 +131,7 @@ Pl_AES_PDF::initializeVector() @@ -136,9 +131,7 @@ Pl_AES_PDF::initializeVector()
136 void 131 void
137 Pl_AES_PDF::flush(bool strip_padding) 132 Pl_AES_PDF::flush(bool strip_padding)
138 { 133 {
139 - if (offset != buf_size) {  
140 - throw std::logic_error("AES pipeline: flush called when buffer was not full");  
141 - } 134 + util::assertion(offset == buf_size, "AES pipeline: flush called when buffer was not full");
142 135
143 if (first) { 136 if (first) {
144 first = false; 137 first = false;
libqpdf/Pl_ASCII85Decoder.cc
1 #include <qpdf/Pl_ASCII85Decoder.hh> 1 #include <qpdf/Pl_ASCII85Decoder.hh>
2 2
3 #include <qpdf/QTC.hh> 3 #include <qpdf/QTC.hh>
  4 +#include <qpdf/Util.hh>
  5 +
4 #include <cstring> 6 #include <cstring>
5 #include <stdexcept> 7 #include <stdexcept>
6 8
  9 +using namespace qpdf;
  10 +
7 Pl_ASCII85Decoder::Pl_ASCII85Decoder(char const* identifier, Pipeline* next) : 11 Pl_ASCII85Decoder::Pl_ASCII85Decoder(char const* identifier, Pipeline* next) :
8 Pipeline(identifier, next) 12 Pipeline(identifier, next)
9 { 13 {
10 - if (!next) {  
11 - throw std::logic_error("Attempt to create Pl_ASCII85Decoder with nullptr as next");  
12 - } 14 + util::assertion(next, "Attempt to create Pl_ASCII85Decoder with nullptr as next");
13 } 15 }
14 16
15 void 17 void
@@ -33,12 +35,9 @@ Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len) @@ -33,12 +35,9 @@ Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len)
33 if (eod > 1) { 35 if (eod > 1) {
34 break; 36 break;
35 } else if (eod == 1) { 37 } else if (eod == 1) {
36 - if (buf[i] == '>') {  
37 - flush();  
38 - eod = 2;  
39 - } else {  
40 - throw std::runtime_error("broken end-of-data sequence in base 85 data");  
41 - } 38 + util::no_ci_rt_error_if(buf[i] != '>', "broken end-of-data sequence in base 85 data");
  39 + flush();
  40 + eod = 2;
42 } else { 41 } else {
43 switch (buf[i]) { 42 switch (buf[i]) {
44 case '~': 43 case '~':
@@ -48,12 +47,10 @@ Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len) @@ -48,12 +47,10 @@ Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len)
48 case 'z': 47 case 'z':
49 if (pos != 0) { 48 if (pos != 0) {
50 throw std::runtime_error("unexpected z during base 85 decode"); 49 throw std::runtime_error("unexpected z during base 85 decode");
51 - } else {  
52 - QTC::TC("libtests", "Pl_ASCII85Decoder read z");  
53 - unsigned char zeroes[4];  
54 - memset(zeroes, '\0', 4);  
55 - next()->write(zeroes, 4);  
56 } 50 }
  51 + unsigned char zeroes[4];
  52 + memset(zeroes, '\0', 4);
  53 + next()->write(zeroes, 4);
57 break; 54 break;
58 55
59 default: 56 default:
@@ -76,7 +73,6 @@ void @@ -76,7 +73,6 @@ void
76 Pl_ASCII85Decoder::flush() 73 Pl_ASCII85Decoder::flush()
77 { 74 {
78 if (this->pos == 0) { 75 if (this->pos == 0) {
79 - QTC::TC("libtests", "Pl_ASCII85Decoder no-op flush");  
80 return; 76 return;
81 } 77 }
82 unsigned long lval = 0; 78 unsigned long lval = 0;
libqpdf/Pl_ASCIIHexDecoder.cc
1 #include <qpdf/Pl_ASCIIHexDecoder.hh> 1 #include <qpdf/Pl_ASCIIHexDecoder.hh>
2 2
3 #include <qpdf/QTC.hh> 3 #include <qpdf/QTC.hh>
  4 +#include <qpdf/Util.hh>
  5 +
4 #include <cctype> 6 #include <cctype>
5 #include <stdexcept> 7 #include <stdexcept>
6 8
  9 +using namespace qpdf;
7 using namespace std::literals; 10 using namespace std::literals;
8 11
9 Pl_ASCIIHexDecoder::Pl_ASCIIHexDecoder(char const* identifier, Pipeline* next) : 12 Pl_ASCIIHexDecoder::Pl_ASCIIHexDecoder(char const* identifier, Pipeline* next) :
10 Pipeline(identifier, next) 13 Pipeline(identifier, next)
11 { 14 {
12 - if (!next) {  
13 - throw std::logic_error("Attempt to create Pl_ASCIIHexDecoder with nullptr as next");  
14 - } 15 + util::assertion(next, "Attempt to create Pl_ASCIIHexDecoder with nullptr as next");
15 } 16 }
16 17
17 void 18 void
libqpdf/Pl_Buffer.cc
1 #include <qpdf/Pl_Buffer.hh> 1 #include <qpdf/Pl_Buffer.hh>
2 2
  3 +#include <qpdf/Util.hh>
  4 +
3 #include <algorithm> 5 #include <algorithm>
4 #include <cstdlib> 6 #include <cstdlib>
5 #include <cstring> 7 #include <cstring>
6 #include <stdexcept> 8 #include <stdexcept>
7 9
  10 +using namespace qpdf;
  11 +
8 class Pl_Buffer::Members 12 class Pl_Buffer::Members
9 { 13 {
10 public: 14 public:
@@ -50,9 +54,7 @@ Pl_Buffer::finish() @@ -50,9 +54,7 @@ Pl_Buffer::finish()
50 Buffer* 54 Buffer*
51 Pl_Buffer::getBuffer() 55 Pl_Buffer::getBuffer()
52 { 56 {
53 - if (!m->ready) {  
54 - throw std::logic_error("Pl_Buffer::getBuffer() called when not ready");  
55 - } 57 + util::assertion(m->ready, "Pl_Buffer::getBuffer() called when not ready");
56 auto* b = new Buffer(std::move(m->data)); 58 auto* b = new Buffer(std::move(m->data));
57 m->data.clear(); 59 m->data.clear();
58 return b; 60 return b;
@@ -61,9 +63,7 @@ Pl_Buffer::getBuffer() @@ -61,9 +63,7 @@ Pl_Buffer::getBuffer()
61 std::string 63 std::string
62 Pl_Buffer::getString() 64 Pl_Buffer::getString()
63 { 65 {
64 - if (!m->ready) {  
65 - throw std::logic_error("Pl_Buffer::getString() called when not ready");  
66 - } 66 + util::assertion(m->ready, "Pl_Buffer::getString() called when not ready");
67 auto s = std::move(m->data); 67 auto s = std::move(m->data);
68 m->data.clear(); 68 m->data.clear();
69 return s; 69 return s;
@@ -78,9 +78,7 @@ Pl_Buffer::getBufferSharedPointer() @@ -78,9 +78,7 @@ Pl_Buffer::getBufferSharedPointer()
78 void 78 void
79 Pl_Buffer::getMallocBuffer(unsigned char** buf, size_t* len) 79 Pl_Buffer::getMallocBuffer(unsigned char** buf, size_t* len)
80 { 80 {
81 - if (!m->ready) {  
82 - throw std::logic_error("Pl_Buffer::getMallocBuffer() called when not ready");  
83 - } 81 + util::assertion(m->ready, "Pl_Buffer::getMallocBuffer() called when not ready");
84 auto size = m->data.size(); 82 auto size = m->data.size();
85 *len = size; 83 *len = size;
86 if (size > 0) { 84 if (size > 0) {
libqpdf/Pl_Concatenate.cc
1 #include <qpdf/Pl_Concatenate.hh> 1 #include <qpdf/Pl_Concatenate.hh>
2 2
3 -#include <stdexcept> 3 +#include <qpdf/Util.hh>
  4 +
  5 +using namespace qpdf;
4 6
5 Pl_Concatenate::Pl_Concatenate(char const* identifier, Pipeline* next) : 7 Pl_Concatenate::Pl_Concatenate(char const* identifier, Pipeline* next) :
6 Pipeline(identifier, next) 8 Pipeline(identifier, next)
7 { 9 {
8 - if (!next) {  
9 - throw std::logic_error("Attempt to create Pl_Concatenate with nullptr as next");  
10 - } 10 + util::assertion(next, "Attempt to create Pl_Concatenate with nullptr as next");
11 } 11 }
12 12
13 // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer 13 // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer
libqpdf/Pl_Count.cc
1 #include <qpdf/Pl_Count.hh> 1 #include <qpdf/Pl_Count.hh>
2 2
3 #include <qpdf/QIntC.hh> 3 #include <qpdf/QIntC.hh>
  4 +#include <qpdf/Util.hh>
  5 +
  6 +using namespace qpdf;
4 7
5 class Pl_Count::Members 8 class Pl_Count::Members
6 { 9 {
@@ -18,15 +21,11 @@ Pl_Count::Pl_Count(char const* identifier, Pipeline* next) : @@ -18,15 +21,11 @@ Pl_Count::Pl_Count(char const* identifier, Pipeline* next) :
18 Pipeline(identifier, next), 21 Pipeline(identifier, next),
19 m(std::make_unique<Members>()) 22 m(std::make_unique<Members>())
20 { 23 {
21 - if (!next) {  
22 - throw std::logic_error("Attempt to create Pl_Count with nullptr as next");  
23 - } 24 + util::assertion(next, "Attempt to create Pl_Count with nullptr as next");
24 } 25 }
25 26
26 -Pl_Count::~Pl_Count() // NOLINT (modernize-use-equals-default)  
27 -{  
28 - // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer  
29 -} 27 +Pl_Count::~Pl_Count() = default;
  28 +// Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer
30 29
31 void 30 void
32 Pl_Count::write(unsigned char const* buf, size_t len) 31 Pl_Count::write(unsigned char const* buf, size_t len)
libqpdf/Pl_DCT.cc
@@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
2 2
3 #include <qpdf/QIntC.hh> 3 #include <qpdf/QIntC.hh>
4 #include <qpdf/QTC.hh> 4 #include <qpdf/QTC.hh>
  5 +#include <qpdf/Util.hh>
5 6
6 #include <csetjmp> 7 #include <csetjmp>
7 #include <stdexcept> 8 #include <stdexcept>
@@ -11,6 +12,8 @@ @@ -11,6 +12,8 @@
11 # error "qpdf does not support libjpeg built with BITS_IN_JSAMPLE != 8" 12 # error "qpdf does not support libjpeg built with BITS_IN_JSAMPLE != 8"
12 #endif 13 #endif
13 14
  15 +using namespace qpdf;
  16 +
14 namespace 17 namespace
15 { 18 {
16 class FunctionCallbackConfig: public Pl_DCT::CompressConfig 19 class FunctionCallbackConfig: public Pl_DCT::CompressConfig
@@ -118,9 +121,7 @@ Pl_DCT::Pl_DCT(char const* identifier, Pipeline* next) : @@ -118,9 +121,7 @@ Pl_DCT::Pl_DCT(char const* identifier, Pipeline* next) :
118 Pipeline(identifier, next), 121 Pipeline(identifier, next),
119 m(std::make_unique<Members>()) 122 m(std::make_unique<Members>())
120 { 123 {
121 - if (!next) {  
122 - throw std::logic_error("Attempt to create Pl_DCT with nullptr as next");  
123 - } 124 + util::assertion(next, "Attempt to create Pl_DCT with nullptr as next");
124 } 125 }
125 126
126 void 127 void
@@ -285,12 +286,10 @@ fill_buffer_input_buffer(j_decompress_ptr) @@ -285,12 +286,10 @@ fill_buffer_input_buffer(j_decompress_ptr)
285 static void 286 static void
286 skip_buffer_input_data(j_decompress_ptr cinfo, long num_bytes) 287 skip_buffer_input_data(j_decompress_ptr cinfo, long num_bytes)
287 { 288 {
288 - if (num_bytes < 0) {  
289 - throw std::runtime_error(  
290 - "reading jpeg: jpeg library requested skipping a negative number of bytes");  
291 - } 289 + util::no_ci_rt_error_if(
  290 + num_bytes < 0, "reading jpeg: jpeg library requested skipping a negative number of bytes");
292 size_t to_skip = QIntC::to_size(num_bytes); 291 size_t to_skip = QIntC::to_size(num_bytes);
293 - if ((to_skip > 0) && (to_skip <= cinfo->src->bytes_in_buffer)) { 292 + if (to_skip > 0 && to_skip <= cinfo->src->bytes_in_buffer) {
294 cinfo->src->next_input_byte += to_skip; 293 cinfo->src->next_input_byte += to_skip;
295 cinfo->src->bytes_in_buffer -= to_skip; 294 cinfo->src->bytes_in_buffer -= to_skip;
296 } else if (to_skip != 0) { 295 } else if (to_skip != 0) {
@@ -354,11 +353,10 @@ Pl_DCT::compress(void* cinfo_p) @@ -354,11 +353,10 @@ Pl_DCT::compress(void* cinfo_p)
354 unsigned int width = cinfo->image_width * QIntC::to_uint(cinfo->input_components); 353 unsigned int width = cinfo->image_width * QIntC::to_uint(cinfo->input_components);
355 size_t expected_size = QIntC::to_size(cinfo->image_height) * 354 size_t expected_size = QIntC::to_size(cinfo->image_height) *
356 QIntC::to_size(cinfo->image_width) * QIntC::to_size(cinfo->input_components); 355 QIntC::to_size(cinfo->image_width) * QIntC::to_size(cinfo->input_components);
357 - if (m->buf.size() != expected_size) {  
358 - throw std::runtime_error(  
359 - "Pl_DCT: image buffer size = " + std::to_string(m->buf.size()) + 356 + util::no_ci_rt_error_if(
  357 + m->buf.size() != expected_size,
  358 + "Pl_DCT: image buffer size = " + std::to_string(m->buf.size()) +
360 "; expected size = " + std::to_string(expected_size)); 359 "; expected size = " + std::to_string(expected_size));
361 - }  
362 JSAMPROW row_pointer[1]; 360 JSAMPROW row_pointer[1];
363 auto buffer = reinterpret_cast<unsigned char*>(m->buf.data()); 361 auto buffer = reinterpret_cast<unsigned char*>(m->buf.data());
364 while (cinfo->next_scanline < cinfo->image_height) { 362 while (cinfo->next_scanline < cinfo->image_height) {
libqpdf/Pl_Flate.cc
@@ -6,12 +6,15 @@ @@ -6,12 +6,15 @@
6 6
7 #include <qpdf/QIntC.hh> 7 #include <qpdf/QIntC.hh>
8 #include <qpdf/QUtil.hh> 8 #include <qpdf/QUtil.hh>
  9 +#include <qpdf/Util.hh>
9 #include <qpdf/qpdf-config.h> 10 #include <qpdf/qpdf-config.h>
10 11
11 #ifdef ZOPFLI 12 #ifdef ZOPFLI
12 # include <zopfli.h> 13 # include <zopfli.h>
13 #endif 14 #endif
14 15
  16 +using namespace qpdf;
  17 +
15 namespace 18 namespace
16 { 19 {
17 unsigned long long memory_limit_{0}; 20 unsigned long long memory_limit_{0};
@@ -31,10 +34,9 @@ Pl_Flate::Members::Members(size_t out_bufsize, action_e action) : @@ -31,10 +34,9 @@ Pl_Flate::Members::Members(size_t out_bufsize, action_e action) :
31 // development files available, which particularly helps in a Windows environment. 34 // development files available, which particularly helps in a Windows environment.
32 zdata = new z_stream; 35 zdata = new z_stream;
33 36
34 - if (out_bufsize > UINT_MAX) {  
35 - throw std::runtime_error(  
36 - "Pl_Flate: zlib doesn't support buffer sizes larger than unsigned int");  
37 - } 37 + util::no_ci_rt_error_if(
  38 + out_bufsize > UINT_MAX,
  39 + "Pl_Flate: zlib doesn't support buffer sizes larger than unsigned int");
38 40
39 z_stream& zstream = *(static_cast<z_stream*>(this->zdata)); 41 z_stream& zstream = *(static_cast<z_stream*>(this->zdata));
40 zstream.zalloc = nullptr; 42 zstream.zalloc = nullptr;
@@ -70,9 +72,7 @@ Pl_Flate::Pl_Flate( @@ -70,9 +72,7 @@ Pl_Flate::Pl_Flate(
70 Pipeline(identifier, next), 72 Pipeline(identifier, next),
71 m(std::make_unique<Members>(QIntC::to_size(out_bufsize_int), action)) 73 m(std::make_unique<Members>(QIntC::to_size(out_bufsize_int), action))
72 { 74 {
73 - if (!next) {  
74 - throw std::logic_error("Attempt to create Pl_Flate with nullptr as next");  
75 - } 75 + util::assertion(next, "Attempt to create Pl_Flate with nullptr as next");
76 } 76 }
77 77
78 // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer 78 // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer
@@ -107,10 +107,8 @@ Pl_Flate::warn(char const* msg, int code) @@ -107,10 +107,8 @@ Pl_Flate::warn(char const* msg, int code)
107 void 107 void
108 Pl_Flate::write(unsigned char const* data, size_t len) 108 Pl_Flate::write(unsigned char const* data, size_t len)
109 { 109 {
110 - if (!m->outbuf) {  
111 - throw std::logic_error(  
112 - this->identifier + ": Pl_Flate: write() called after finish() called");  
113 - } 110 + util::assertion(
  111 + m->outbuf.get(), identifier + ": Pl_Flate: write() called after finish() called");
114 if (m->zopfli_buf) { 112 if (m->zopfli_buf) {
115 m->zopfli_buf->append(reinterpret_cast<char const*>(data), len); 113 m->zopfli_buf->append(reinterpret_cast<char const*>(data), len);
116 return; 114 return;
@@ -131,9 +129,8 @@ Pl_Flate::write(unsigned char const* data, size_t len) @@ -131,9 +129,8 @@ Pl_Flate::write(unsigned char const* data, size_t len)
131 void 129 void
132 Pl_Flate::handleData(unsigned char const* data, size_t len, int flush) 130 Pl_Flate::handleData(unsigned char const* data, size_t len, int flush)
133 { 131 {
134 - if (len > UINT_MAX) {  
135 - throw std::runtime_error("Pl_Flate: zlib doesn't support data blocks larger than int");  
136 - } 132 + util::no_ci_rt_error_if(
  133 + len > UINT_MAX, "Pl_Flate: zlib doesn't support data blocks larger than int");
137 z_stream& zstream = *(static_cast<z_stream*>(m->zdata)); 134 z_stream& zstream = *(static_cast<z_stream*>(m->zdata));
138 // zlib is known not to modify the data pointed to by next_in but doesn't declare the field 135 // zlib is known not to modify the data pointed to by next_in but doesn't declare the field
139 // value const unless compiled to do so. 136 // value const unless compiled to do so.
@@ -216,7 +213,6 @@ Pl_Flate::handleData(unsigned char const* data, size_t len, int flush) @@ -216,7 +213,6 @@ Pl_Flate::handleData(unsigned char const* data, size_t len, int flush)
216 213
217 default: 214 default:
218 checkError("data", err); 215 checkError("data", err);
219 - break;  
220 } 216 }
221 } 217 }
222 } 218 }
libqpdf/Pl_LZWDecoder.cc
@@ -2,17 +2,17 @@ @@ -2,17 +2,17 @@
2 2
3 #include <qpdf/QIntC.hh> 3 #include <qpdf/QIntC.hh>
4 #include <qpdf/QTC.hh> 4 #include <qpdf/QTC.hh>
5 -#include <qpdf/QUtil.hh> 5 +#include <qpdf/Util.hh>
6 #include <cstring> 6 #include <cstring>
7 #include <stdexcept> 7 #include <stdexcept>
8 8
  9 +using namespace qpdf;
  10 +
9 Pl_LZWDecoder::Pl_LZWDecoder(char const* identifier, Pipeline* next, bool early_code_change) : 11 Pl_LZWDecoder::Pl_LZWDecoder(char const* identifier, Pipeline* next, bool early_code_change) :
10 Pipeline(identifier, next), 12 Pipeline(identifier, next),
11 code_change_delta(early_code_change) 13 code_change_delta(early_code_change)
12 { 14 {
13 - if (!next) {  
14 - throw std::logic_error("Attempt to create Pl_LZWDecoder with nullptr as next");  
15 - } 15 + util::assertion(next, "Attempt to create Pl_LZWDecoder with nullptr as next");
16 } 16 }
17 17
18 void 18 void
@@ -78,21 +78,17 @@ Pl_LZWDecoder::sendNextCode() @@ -78,21 +78,17 @@ Pl_LZWDecoder::sendNextCode()
78 unsigned char 78 unsigned char
79 Pl_LZWDecoder::getFirstChar(unsigned int code) 79 Pl_LZWDecoder::getFirstChar(unsigned int code)
80 { 80 {
81 - unsigned char result = '\0';  
82 if (code < 256) { 81 if (code < 256) {
83 - result = static_cast<unsigned char>(code);  
84 - } else if (code > 257) {  
85 - unsigned int idx = code - 258;  
86 - if (idx >= table.size()) {  
87 - throw std::runtime_error("Pl_LZWDecoder::getFirstChar: table overflow");  
88 - }  
89 - Buffer& b = table.at(idx);  
90 - result = b.getBuffer()[0];  
91 - } else {  
92 - throw std::runtime_error(  
93 - "Pl_LZWDecoder::getFirstChar called with invalid code (" + std::to_string(code) + ")"); 82 + return static_cast<unsigned char>(code);
94 } 83 }
95 - return result; 84 + util::no_ci_rt_error_if(
  85 + code <= 257,
  86 + "Pl_LZWDecoder::getFirstChar called with invalid code (" + std::to_string(code) + ")");
  87 +
  88 + unsigned int idx = code - 258;
  89 + util::no_ci_rt_error_if(idx >= table.size(), "Pl_LZWDecoder::getFirstChar: table overflow");
  90 + Buffer& b = table.at(idx);
  91 + return b.getBuffer()[0];
96 } 92 }
97 93
98 void 94 void
@@ -106,18 +102,16 @@ Pl_LZWDecoder::addToTable(unsigned char c) @@ -106,18 +102,16 @@ Pl_LZWDecoder::addToTable(unsigned char c)
106 tmp[0] = static_cast<unsigned char>(last_code); 102 tmp[0] = static_cast<unsigned char>(last_code);
107 last_data = tmp; 103 last_data = tmp;
108 last_size = 1; 104 last_size = 1;
109 - } else if (last_code > 257) { 105 + } else {
  106 + util::no_ci_rt_error_if(
  107 + last_code <= 257,
  108 + "Pl_LZWDecoder::addToTable called with invalid code (" + std::to_string(last_code) +
  109 + ")");
110 unsigned int idx = last_code - 258; 110 unsigned int idx = last_code - 258;
111 - if (idx >= table.size()) {  
112 - throw std::runtime_error("Pl_LZWDecoder::addToTable: table overflow");  
113 - } 111 + util::no_ci_rt_error_if(idx >= table.size(), "Pl_LZWDecoder::addToTable: table overflow");
114 Buffer& b = table.at(idx); 112 Buffer& b = table.at(idx);
115 last_data = b.getBuffer(); 113 last_data = b.getBuffer();
116 last_size = QIntC::to_uint(b.getSize()); 114 last_size = QIntC::to_uint(b.getSize());
117 - } else {  
118 - throw std::runtime_error(  
119 - "Pl_LZWDecoder::addToTable called with invalid code (" + std::to_string(last_code) +  
120 - ")");  
121 } 115 }
122 116
123 Buffer entry(1 + last_size); 117 Buffer entry(1 + last_size);
@@ -158,19 +152,16 @@ Pl_LZWDecoder::handleCode(unsigned int code) @@ -158,19 +152,16 @@ Pl_LZWDecoder::handleCode(unsigned int code)
158 } else if (idx == table_size) { 152 } else if (idx == table_size) {
159 // The encoder would have just created this entry, so the first character of 153 // The encoder would have just created this entry, so the first character of
160 // this entry would have been the same as the first character of the last entry. 154 // this entry would have been the same as the first character of the last entry.
161 - QTC::TC("libtests", "Pl_LZWDecoder last was table size");  
162 next_c = getFirstChar(last_code); 155 next_c = getFirstChar(last_code);
163 } else { 156 } else {
164 next_c = getFirstChar(code); 157 next_c = getFirstChar(code);
165 } 158 }
166 } 159 }
167 unsigned int new_idx = 258 + table_size; 160 unsigned int new_idx = 258 + table_size;
168 - if (new_idx == 4096) {  
169 - throw std::runtime_error("LZWDecoder: table full");  
170 - } 161 + util::no_ci_rt_error_if(new_idx == 4096, "LZWDecoder: table full");
171 addToTable(next_c); 162 addToTable(next_c);
172 unsigned int change_idx = new_idx + code_change_delta; 163 unsigned int change_idx = new_idx + code_change_delta;
173 - if ((change_idx == 511) || (change_idx == 1023) || (change_idx == 2047)) { 164 + if (change_idx == 511 || change_idx == 1023 || change_idx == 2047) {
174 ++code_size; 165 ++code_size;
175 } 166 }
176 } 167 }
libqpdf/Pl_RC4.cc
1 #include <qpdf/Pl_RC4.hh> 1 #include <qpdf/Pl_RC4.hh>
2 2
3 #include <qpdf/QUtil.hh> 3 #include <qpdf/QUtil.hh>
  4 +#include <qpdf/Util.hh>
  5 +
  6 +using namespace qpdf;
4 7
5 Pl_RC4::Pl_RC4(char const* identifier, Pipeline* next, std::string key, size_t out_bufsize) : 8 Pl_RC4::Pl_RC4(char const* identifier, Pipeline* next, std::string key, size_t out_bufsize) :
6 Pipeline(identifier, next), 9 Pipeline(identifier, next),
7 out_bufsize(out_bufsize), 10 out_bufsize(out_bufsize),
8 rc4(reinterpret_cast<unsigned char const*>(key.data()), static_cast<int>(key.size())) 11 rc4(reinterpret_cast<unsigned char const*>(key.data()), static_cast<int>(key.size()))
9 { 12 {
10 - if (!next) {  
11 - throw std::logic_error("Attempt to create Pl_RC4 with nullptr as next");  
12 - } 13 + util::assertion(next, "Attempt to create Pl_RC4 with nullptr as next");
13 this->outbuf = QUtil::make_shared_array<unsigned char>(out_bufsize); 14 this->outbuf = QUtil::make_shared_array<unsigned char>(out_bufsize);
14 } 15 }
15 16
16 void 17 void
17 Pl_RC4::write(unsigned char const* data, size_t len) 18 Pl_RC4::write(unsigned char const* data, size_t len)
18 { 19 {
19 - if (this->outbuf == nullptr) {  
20 - throw std::logic_error(this->identifier + ": Pl_RC4: write() called after finish() called");  
21 - } 20 + util::assertion(outbuf.get(), "Pl_RC4: write() called after finish() called");
22 21
23 size_t bytes_left = len; 22 size_t bytes_left = len;
24 unsigned char const* p = data; 23 unsigned char const* p = data;
@@ -26,7 +25,6 @@ Pl_RC4::write(unsigned char const* data, size_t len) @@ -26,7 +25,6 @@ Pl_RC4::write(unsigned char const* data, size_t len)
26 while (bytes_left > 0) { 25 while (bytes_left > 0) {
27 size_t bytes = (bytes_left < this->out_bufsize ? bytes_left : out_bufsize); 26 size_t bytes = (bytes_left < this->out_bufsize ? bytes_left : out_bufsize);
28 bytes_left -= bytes; 27 bytes_left -= bytes;
29 - // lgtm[cpp/weak-cryptographic-algorithm]  
30 rc4.process(p, bytes, outbuf.get()); 28 rc4.process(p, bytes, outbuf.get());
31 p += bytes; 29 p += bytes;
32 next()->write(outbuf.get(), bytes); 30 next()->write(outbuf.get(), bytes);
libqpdf/Pl_SHA2.cc
@@ -2,8 +2,9 @@ @@ -2,8 +2,9 @@
2 2
3 #include <qpdf/QPDFCryptoProvider.hh> 3 #include <qpdf/QPDFCryptoProvider.hh>
4 #include <qpdf/QUtil.hh> 4 #include <qpdf/QUtil.hh>
  5 +#include <qpdf/Util.hh>
5 6
6 -#include <stdexcept> 7 +using namespace qpdf;
7 8
8 Pl_SHA2::Pl_SHA2(int bits, Pipeline* next) : 9 Pl_SHA2::Pl_SHA2(int bits, Pipeline* next) :
9 Pipeline("sha2", next) 10 Pipeline("sha2", next)
@@ -49,9 +50,7 @@ Pl_SHA2::finish() @@ -49,9 +50,7 @@ Pl_SHA2::finish()
49 void 50 void
50 Pl_SHA2::resetBits(int bits) 51 Pl_SHA2::resetBits(int bits)
51 { 52 {
52 - if (in_progress) {  
53 - throw std::logic_error("bit reset requested for in-progress SHA2 Pipeline");  
54 - } 53 + util::assertion(!in_progress, "bit reset requested for in-progress SHA2 Pipeline");
55 crypto = QPDFCryptoProvider::getImpl(); 54 crypto = QPDFCryptoProvider::getImpl();
56 crypto->SHA2_init(bits); 55 crypto->SHA2_init(bits);
57 } 56 }
@@ -59,17 +58,13 @@ Pl_SHA2::resetBits(int bits) @@ -59,17 +58,13 @@ Pl_SHA2::resetBits(int bits)
59 std::string 58 std::string
60 Pl_SHA2::getRawDigest() 59 Pl_SHA2::getRawDigest()
61 { 60 {
62 - if (in_progress) {  
63 - throw std::logic_error("digest requested for in-progress SHA2 Pipeline");  
64 - } 61 + util::assertion(!in_progress, "digest requested for in-progress SHA2 Pipeline");
65 return crypto->SHA2_digest(); 62 return crypto->SHA2_digest();
66 } 63 }
67 64
68 std::string 65 std::string
69 Pl_SHA2::getHexDigest() 66 Pl_SHA2::getHexDigest()
70 { 67 {
71 - if (in_progress) {  
72 - throw std::logic_error("digest requested for in-progress SHA2 Pipeline");  
73 - } 68 + util::assertion(!in_progress, "digest requested for in-progress SHA2 Pipeline");
74 return QUtil::hex_encode(getRawDigest()); 69 return QUtil::hex_encode(getRawDigest());
75 } 70 }
libqpdf/QPDF.cc
@@ -672,10 +672,7 @@ QPDF::getXRefTable() @@ -672,10 +672,7 @@ QPDF::getXRefTable()
672 std::map<QPDFObjGen, QPDFXRefEntry> const& 672 std::map<QPDFObjGen, QPDFXRefEntry> const&
673 Objects::xref_table() 673 Objects::xref_table()
674 { 674 {
675 - if (!m->parsed) {  
676 - throw std::logic_error("QPDF::getXRefTable called before parsing.");  
677 - }  
678 - 675 + util::assertion(m->parsed, "QPDF::getXRefTable called before parsing");
679 return m->xref_table; 676 return m->xref_table;
680 } 677 }
681 678
libqpdf/QPDFArgParser.cc
@@ -56,7 +56,6 @@ QPDFArgParser::selectOptionTable(std::string const&amp; name) @@ -56,7 +56,6 @@ QPDFArgParser::selectOptionTable(std::string const&amp; name)
56 { 56 {
57 auto t = m->option_tables.find(name); 57 auto t = m->option_tables.find(name);
58 if (t == m->option_tables.end()) { 58 if (t == m->option_tables.end()) {
59 - QTC::TC("libtests", "QPDFArgParser select unregistered table");  
60 throw std::logic_error("QPDFArgParser: selecting unregistered option table " + name); 59 throw std::logic_error("QPDFArgParser: selecting unregistered option table " + name);
61 } 60 }
62 m->option_table = &(t->second); 61 m->option_table = &(t->second);
@@ -67,7 +66,6 @@ void @@ -67,7 +66,6 @@ void
67 QPDFArgParser::registerOptionTable(std::string const& name, bare_arg_handler_t end_handler) 66 QPDFArgParser::registerOptionTable(std::string const& name, bare_arg_handler_t end_handler)
68 { 67 {
69 if (m->option_tables.contains(name)) { 68 if (m->option_tables.contains(name)) {
70 - QTC::TC("libtests", "QPDFArgParser register registered table");  
71 throw std::logic_error( 69 throw std::logic_error(
72 "QPDFArgParser: registering already registered option table " + name); 70 "QPDFArgParser: registering already registered option table " + name);
73 } 71 }
@@ -80,7 +78,6 @@ QPDFArgParser::OptionEntry&amp; @@ -80,7 +78,6 @@ QPDFArgParser::OptionEntry&amp;
80 QPDFArgParser::registerArg(std::string const& arg) 78 QPDFArgParser::registerArg(std::string const& arg)
81 { 79 {
82 if (m->option_table->contains(arg)) { 80 if (m->option_table->contains(arg)) {
83 - QTC::TC("libtests", "QPDFArgParser duplicate handler");  
84 throw std::logic_error( 81 throw std::logic_error(
85 "QPDFArgParser: adding a duplicate handler for option " + arg + " in " + 82 "QPDFArgParser: adding a duplicate handler for option " + arg + " in " +
86 m->option_table_name + " option table"); 83 m->option_table_name + " option table");
@@ -138,7 +135,6 @@ QPDFArgParser::addInvalidChoiceHandler(std::string const&amp; arg, param_arg_handler @@ -138,7 +135,6 @@ QPDFArgParser::addInvalidChoiceHandler(std::string const&amp; arg, param_arg_handler
138 { 135 {
139 auto i = m->option_table->find(arg); 136 auto i = m->option_table->find(arg);
140 if (i == m->option_table->end()) { 137 if (i == m->option_table->end()) {
141 - QTC::TC("libtests", "QPDFArgParser invalid choice handler to unknown");  
142 throw std::logic_error( 138 throw std::logic_error(
143 "QPDFArgParser: attempt to add invalid choice handler to unknown argument"); 139 "QPDFArgParser: attempt to add invalid choice handler to unknown argument");
144 } 140 }
@@ -448,11 +444,9 @@ QPDFArgParser::parseArgs() @@ -448,11 +444,9 @@ QPDFArgParser::parseArgs()
448 // Special case for -- option, which is used to break out of subparsers. 444 // Special case for -- option, which is used to break out of subparsers.
449 oep = m->option_table->find("--"); 445 oep = m->option_table->find("--");
450 end_option = true; 446 end_option = true;
451 - if (oep == m->option_table->end()) {  
452 - // This is registered automatically, so this can't happen.  
453 - throw std::logic_error("QPDFArgParser: -- handler not registered");  
454 - }  
455 - } else if ((arg[0] == '-') && (strcmp(arg, "-") != 0)) { 447 + util::internal_error_if(
  448 + oep == m->option_table->end(), "QPDFArgParser: -- handler not registered");
  449 + } else if (arg[0] == '-' && strcmp(arg, "-") != 0) {
456 ++arg; 450 ++arg;
457 if (arg[0] == '-') { 451 if (arg[0] == '-') {
458 // Be lax about -arg vs --arg 452 // Be lax about -arg vs --arg
@@ -678,15 +672,12 @@ QPDFArgParser::addHelpTopic( @@ -678,15 +672,12 @@ QPDFArgParser::addHelpTopic(
678 std::string const& topic, std::string const& short_text, std::string const& long_text) 672 std::string const& topic, std::string const& short_text, std::string const& long_text)
679 { 673 {
680 if (topic == "all") { 674 if (topic == "all") {
681 - QTC::TC("libtests", "QPDFArgParser add reserved help topic");  
682 throw std::logic_error("QPDFArgParser: can't register reserved help topic " + topic); 675 throw std::logic_error("QPDFArgParser: can't register reserved help topic " + topic);
683 } 676 }
684 if (topic.empty() || topic.at(0) == '-') { 677 if (topic.empty() || topic.at(0) == '-') {
685 - QTC::TC("libtests", "QPDFArgParser bad topic for help");  
686 throw std::logic_error("QPDFArgParser: help topics must not start with -"); 678 throw std::logic_error("QPDFArgParser: help topics must not start with -");
687 } 679 }
688 if (m->help_topics.contains(topic)) { 680 if (m->help_topics.contains(topic)) {
689 - QTC::TC("libtests", "QPDFArgParser add existing topic");  
690 throw std::logic_error("QPDFArgParser: topic " + topic + " has already been added"); 681 throw std::logic_error("QPDFArgParser: topic " + topic + " has already been added");
691 } 682 }
692 683
@@ -701,17 +692,14 @@ QPDFArgParser::addOptionHelp( @@ -701,17 +692,14 @@ QPDFArgParser::addOptionHelp(
701 std::string const& short_text, 692 std::string const& short_text,
702 std::string const& long_text) 693 std::string const& long_text)
703 { 694 {
704 - if (!((option_name.length() > 2) && (option_name.at(0) == '-') && (option_name.at(1) == '-'))) {  
705 - QTC::TC("libtests", "QPDFArgParser bad option for help"); 695 + if (!(option_name.length() > 2 && option_name.starts_with("--"))) {
706 throw std::logic_error("QPDFArgParser: options for help must start with --"); 696 throw std::logic_error("QPDFArgParser: options for help must start with --");
707 } 697 }
708 if (m->option_help.contains(option_name)) { 698 if (m->option_help.contains(option_name)) {
709 - QTC::TC("libtests", "QPDFArgParser duplicate option help");  
710 throw std::logic_error("QPDFArgParser: option " + option_name + " already has help"); 699 throw std::logic_error("QPDFArgParser: option " + option_name + " already has help");
711 } 700 }
712 auto ht = m->help_topics.find(topic); 701 auto ht = m->help_topics.find(topic);
713 if (ht == m->help_topics.end()) { 702 if (ht == m->help_topics.end()) {
714 - QTC::TC("libtests", "QPDFArgParser add to unknown topic");  
715 throw std::logic_error( 703 throw std::logic_error(
716 "QPDFArgParser: unable to add option " + option_name + " to unknown help topic " + 704 "QPDFArgParser: unable to add option " + option_name + " to unknown help topic " +
717 topic); 705 topic);
libqpdf/qpdf/Util.hh
@@ -35,6 +35,14 @@ namespace qpdf::util @@ -35,6 +35,14 @@ namespace qpdf::util
35 } 35 }
36 } 36 }
37 37
  38 + inline void
  39 + no_ci_rt_error_if(bool cond, std::string const& msg)
  40 + {
  41 + if (cond) {
  42 + throw std::runtime_error(msg);
  43 + }
  44 + }
  45 +
38 inline constexpr char 46 inline constexpr char
39 hex_decode_char(char digit) 47 hex_decode_char(char digit)
40 { 48 {
libtests/libtests.testcov
1 ignored-scope: qpdf 1 ignored-scope: qpdf
2 Pl_LZWDecoder intermediate reset 0 2 Pl_LZWDecoder intermediate reset 0
3 -Pl_LZWDecoder last was table size 0  
4 Pl_ASCII85Decoder ignore space 0 3 Pl_ASCII85Decoder ignore space 0
5 -Pl_ASCII85Decoder read z 0  
6 -Pl_ASCII85Decoder no-op flush 0  
7 Pl_ASCII85Decoder partial flush 1 4 Pl_ASCII85Decoder partial flush 1
8 bits leftover 1 5 bits leftover 1
9 bits bit_offset 2 6 bits bit_offset 2
@@ -41,22 +38,12 @@ QPDFArgParser read args from stdin 0 @@ -41,22 +38,12 @@ QPDFArgParser read args from stdin 0
41 QPDFArgParser read args from file 0 38 QPDFArgParser read args from file 0
42 QPDFArgParser required choices 0 39 QPDFArgParser required choices 0
43 QPDFArgParser required parameter 0 40 QPDFArgParser required parameter 0
44 -QPDFArgParser select unregistered table 0  
45 -QPDFArgParser register registered table 0  
46 -QPDFArgParser duplicate handler 0  
47 QPDFArgParser missing -- 0 41 QPDFArgParser missing -- 0
48 QPDFArgParser single dash 0 42 QPDFArgParser single dash 0
49 QPDFArgParser help option 0 43 QPDFArgParser help option 0
50 QPDFArgParser positional 0 44 QPDFArgParser positional 0
51 QPDFArgParser unrecognized 0 45 QPDFArgParser unrecognized 0
52 QPDFArgParser complete choices 0 46 QPDFArgParser complete choices 0
53 -QPDFArgParser add reserved help topic 0  
54 -QPDFArgParser add existing topic 0  
55 -QPDFArgParser add to unknown topic 0  
56 -QPDFArgParser duplicate option help 0  
57 -QPDFArgParser bad option for help 0  
58 -QPDFArgParser bad topic for help 0  
59 -QPDFArgParser invalid choice handler to unknown 0  
60 JSON parse junk after object 0 47 JSON parse junk after object 0
61 JSON parse invalid keyword 0 48 JSON parse invalid keyword 0
62 JSON parse expected colon 0 49 JSON parse expected colon 0
libtests/qtest/qutil/qutil.out
@@ -137,3 +137,8 @@ D:20210209191925Z @@ -137,3 +137,8 @@ D:20210209191925Z
137 done 137 done
138 ---- memory usage 138 ---- memory usage
139 memory usage okay 139 memory usage okay
  140 +---- error handlers
  141 +caught exception: msg2
  142 +caught exception: INTERNAL ERROR: msg4
  143 +This is a qpdf bug. Please report at https://github.com/qpdf/qpdf/issues
  144 +caught exception: msg6
libtests/qutil.cc
@@ -3,6 +3,8 @@ @@ -3,6 +3,8 @@
3 #include <qpdf/Pl_Buffer.hh> 3 #include <qpdf/Pl_Buffer.hh>
4 #include <qpdf/QPDFSystemError.hh> 4 #include <qpdf/QPDFSystemError.hh>
5 #include <qpdf/QUtil.hh> 5 #include <qpdf/QUtil.hh>
  6 +#include <qpdf/Util.hh>
  7 +
6 #include <climits> 8 #include <climits>
7 #include <cstdio> 9 #include <cstdio>
8 #include <cstring> 10 #include <cstring>
@@ -743,6 +745,29 @@ memory_usage_test() @@ -743,6 +745,29 @@ memory_usage_test()
743 std::cout << "memory usage okay" << '\n'; 745 std::cout << "memory usage okay" << '\n';
744 } 746 }
745 747
  748 +void
  749 +error_handler_test()
  750 +{
  751 + qpdf::util::assertion(true, "msg1");
  752 + try {
  753 + qpdf::util::assertion(false, "msg2");
  754 + } catch (std::logic_error const& e) {
  755 + std::cout << "caught exception: " << e.what() << '\n';
  756 + }
  757 + qpdf::util::internal_error_if(false, "msg3");
  758 + try {
  759 + qpdf::util::internal_error_if(true, "msg4");
  760 + } catch (std::logic_error const& e) {
  761 + std::cout << "caught exception: " << e.what() << '\n';
  762 + }
  763 + qpdf::util::no_ci_rt_error_if(false, "msg5");
  764 + try {
  765 + qpdf::util::no_ci_rt_error_if(true, "msg6");
  766 + } catch (std::runtime_error const& e) {
  767 + std::cout << "caught exception: " << e.what() << '\n';
  768 + }
  769 +}
  770 +
746 int 771 int
747 main(int argc, char* argv[]) 772 main(int argc, char* argv[])
748 { 773 {
@@ -782,6 +807,8 @@ main(int argc, char* argv[]) @@ -782,6 +807,8 @@ main(int argc, char* argv[])
782 is_long_long_test(); 807 is_long_long_test();
783 std::cout << "---- memory usage" << '\n'; 808 std::cout << "---- memory usage" << '\n';
784 memory_usage_test(); 809 memory_usage_test();
  810 + std::cout << "---- error handlers" << '\n';
  811 + error_handler_test();
785 } catch (std::exception& e) { 812 } catch (std::exception& e) {
786 std::cout << "unexpected exception: " << e.what() << '\n'; 813 std::cout << "unexpected exception: " << e.what() << '\n';
787 } 814 }