Commit e0720eaa78a56dafe5f5e572387b3a0cc8c88ec9
1 parent
83be2191
Use the default logger for other writes to stdout/stderr
When there is no context for writing output or error messages, use the default logger.
Showing
13 changed files
with
111 additions
and
92 deletions
TODO
| @@ -55,30 +55,10 @@ Output Capture | @@ -55,30 +55,10 @@ Output Capture | ||
| 55 | 55 | ||
| 56 | See https://github.com/qpdf/qpdf/issues/691 | 56 | See https://github.com/qpdf/qpdf/issues/691 |
| 57 | 57 | ||
| 58 | -QPDFLogger maintains pipelines for info, warn, error, and save. | ||
| 59 | - | ||
| 60 | -There is a singleton, default QPDFLogger which all QPDF and QPDFJob | ||
| 61 | -objects get on construction. In most cases, it is not necessary to | ||
| 62 | -override this. Allow QPDFJob and QPDF to be passed a new logger | ||
| 63 | -instance. QPDFJob should pass its QPDFLogger to all QPDF objects it | ||
| 64 | -creates. The main uses cases for this would be for multithreading or | ||
| 65 | -for having a library that uses QPDF privately and modifies logger | ||
| 66 | -settings so that it wouldn't interfere with a downstream library or | ||
| 67 | -application also using qpdf. | ||
| 68 | - | ||
| 69 | There needs to be a C API to QPDFLogger. Use functions like this: | 58 | There needs to be a C API to QPDFLogger. Use functions like this: |
| 70 | 59 | ||
| 71 | void set_info((*f)(char* data, unsigned int len, void* udata), void* udata); | 60 | void set_info((*f)(char* data, unsigned int len, void* udata), void* udata); |
| 72 | 61 | ||
| 73 | -We should probably deprecate the output/error setters in QPDF and | ||
| 74 | -QPDFJob. In the meantime, document that they won't work anymore to set | ||
| 75 | -different outputs with different QPDF objects. We may need to delete | ||
| 76 | -rather than deprecate these methods. | ||
| 77 | - | ||
| 78 | -Find all places in the library that write to stdout/stderr/cout/cerr. | ||
| 79 | -Also find places that raise exceptions if unable to warn. These should | ||
| 80 | -use the global output writer. | ||
| 81 | - | ||
| 82 | 62 | ||
| 83 | QPDFPagesTree | 63 | QPDFPagesTree |
| 84 | ============= | 64 | ============= |
include/qpdf/QPDFLogger.hh
| @@ -33,6 +33,19 @@ class QPDFLogger | @@ -33,6 +33,19 @@ class QPDFLogger | ||
| 33 | QPDF_DLL | 33 | QPDF_DLL |
| 34 | QPDFLogger(); | 34 | QPDFLogger(); |
| 35 | 35 | ||
| 36 | + // Return the default logger. In general, you should use the | ||
| 37 | + // default logger. You can also create your own loggers and use | ||
| 38 | + // them QPDF and QPDFJob objects, but there are few reasons to do | ||
| 39 | + // so. One reason may if you are using multiple QPDF or QPDFJob | ||
| 40 | + // objects in different threads and want to capture output and | ||
| 41 | + // errors to different streams. (Note that a single QPDF or | ||
| 42 | + // QPDFJob can't be safely used from multiple threads, but it is | ||
| 43 | + // safe to use separate QPDF and QPDFJob objects on separate | ||
| 44 | + // threads.) Another possible reason would be if you are writing | ||
| 45 | + // an application that uses the qpdf library directly and qpdf is | ||
| 46 | + // also used by a downstream library or if you are using qpdf from | ||
| 47 | + // a library and don't want to interfere with potential uses of | ||
| 48 | + // qpdf by other libraries or applications. | ||
| 36 | QPDF_DLL | 49 | QPDF_DLL |
| 37 | static std::shared_ptr<QPDFLogger> defaultLogger(); | 50 | static std::shared_ptr<QPDFLogger> defaultLogger(); |
| 38 | 51 |
include/qpdf/QPDFObjectHandle.hh
| @@ -1411,14 +1411,14 @@ class QPDFObjectHandle | @@ -1411,14 +1411,14 @@ class QPDFObjectHandle | ||
| 1411 | // End legacy page helpers | 1411 | // End legacy page helpers |
| 1412 | 1412 | ||
| 1413 | // Issue a warning about this object if possible. If the object | 1413 | // Issue a warning about this object if possible. If the object |
| 1414 | - // has a description, a warning will be issued. Otherwise, if | ||
| 1415 | - // throw_if_no_description is true, throw an exception. Otherwise | ||
| 1416 | - // do nothing. Objects read normally from the file have | 1414 | + // has a description, a warning will be issued using the owning |
| 1415 | + // QPDF as context. Otherwise, a message will be written to the | ||
| 1416 | + // default logger's error stream, which is standard error if not | ||
| 1417 | + // overridden. Objects read normally from the file have | ||
| 1417 | // descriptions. See comments on setObjectDescription for | 1418 | // descriptions. See comments on setObjectDescription for |
| 1418 | // additional details. | 1419 | // additional details. |
| 1419 | QPDF_DLL | 1420 | QPDF_DLL |
| 1420 | - void warnIfPossible( | ||
| 1421 | - std::string const& warning, bool throw_if_no_description = false); | 1421 | + void warnIfPossible(std::string const& warning); |
| 1422 | 1422 | ||
| 1423 | // Initializers for objects. This Factory class gives the QPDF | 1423 | // Initializers for objects. This Factory class gives the QPDF |
| 1424 | // class specific permission to call factory methods without | 1424 | // class specific permission to call factory methods without |
libqpdf/QPDFArgParser.cc
| 1 | #include <qpdf/QPDFArgParser.hh> | 1 | #include <qpdf/QPDFArgParser.hh> |
| 2 | 2 | ||
| 3 | #include <qpdf/QIntC.hh> | 3 | #include <qpdf/QIntC.hh> |
| 4 | +#include <qpdf/QPDFLogger.hh> | ||
| 4 | #include <qpdf/QPDFUsage.hh> | 5 | #include <qpdf/QPDFUsage.hh> |
| 5 | #include <qpdf/QTC.hh> | 6 | #include <qpdf/QTC.hh> |
| 6 | #include <qpdf/QUtil.hh> | 7 | #include <qpdf/QUtil.hh> |
| @@ -235,7 +236,7 @@ QPDFArgParser::argCompletionZsh() | @@ -235,7 +236,7 @@ QPDFArgParser::argCompletionZsh() | ||
| 235 | void | 236 | void |
| 236 | QPDFArgParser::argHelp(std::string const& p) | 237 | QPDFArgParser::argHelp(std::string const& p) |
| 237 | { | 238 | { |
| 238 | - std::cout << getHelp(p); | 239 | + QPDFLogger::defaultLogger()->info(getHelp(p)); |
| 239 | exit(0); | 240 | exit(0); |
| 240 | } | 241 | } |
| 241 | 242 |
libqpdf/QPDFJob_argv.cc
| @@ -14,6 +14,7 @@ | @@ -14,6 +14,7 @@ | ||
| 14 | #include <qpdf/QPDFArgParser.hh> | 14 | #include <qpdf/QPDFArgParser.hh> |
| 15 | #include <qpdf/QPDFCryptoProvider.hh> | 15 | #include <qpdf/QPDFCryptoProvider.hh> |
| 16 | #include <qpdf/QPDFJob.hh> | 16 | #include <qpdf/QPDFJob.hh> |
| 17 | +#include <qpdf/QPDFLogger.hh> | ||
| 17 | #include <qpdf/QTC.hh> | 18 | #include <qpdf/QTC.hh> |
| 18 | #include <qpdf/QUtil.hh> | 19 | #include <qpdf/QUtil.hh> |
| 19 | 20 | ||
| @@ -104,10 +105,10 @@ void | @@ -104,10 +105,10 @@ void | ||
| 104 | ArgParser::argVersion() | 105 | ArgParser::argVersion() |
| 105 | { | 106 | { |
| 106 | auto whoami = this->ap.getProgname(); | 107 | auto whoami = this->ap.getProgname(); |
| 107 | - std::cout << whoami << " version " << QPDF::QPDFVersion() << std::endl | ||
| 108 | - << "Run " << whoami | ||
| 109 | - << " --copyright to see copyright and license information." | ||
| 110 | - << std::endl; | 108 | + *QPDFLogger::defaultLogger()->getInfo() |
| 109 | + << whoami << " version " << QPDF::QPDFVersion() << "\n" | ||
| 110 | + << "Run " << whoami | ||
| 111 | + << " --copyright to see copyright and license information.\n"; | ||
| 111 | } | 112 | } |
| 112 | 113 | ||
| 113 | void | 114 | void |
| @@ -117,48 +118,35 @@ ArgParser::argCopyright() | @@ -117,48 +118,35 @@ ArgParser::argCopyright() | ||
| 117 | // Make sure the output looks right on an 80-column display. | 118 | // Make sure the output looks right on an 80-column display. |
| 118 | // 1 2 3 4 5 6 7 8 | 119 | // 1 2 3 4 5 6 7 8 |
| 119 | // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 | 120 | // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 |
| 120 | - std::cout | 121 | + *QPDFLogger::defaultLogger()->getInfo() |
| 121 | << this->ap.getProgname() | 122 | << this->ap.getProgname() |
| 122 | - << " version " << QPDF::QPDFVersion() << std::endl | ||
| 123 | - << std::endl | ||
| 124 | - << "Copyright (c) 2005-2022 Jay Berkenbilt" | ||
| 125 | - << std::endl | ||
| 126 | - << "QPDF is licensed under the Apache License, Version 2.0 (the \"License\");" | ||
| 127 | - << std::endl | ||
| 128 | - << "you may not use this file except in compliance with the License." | ||
| 129 | - << std::endl | ||
| 130 | - << "You may obtain a copy of the License at" | ||
| 131 | - << std::endl | ||
| 132 | - << std::endl | ||
| 133 | - << " http://www.apache.org/licenses/LICENSE-2.0" | ||
| 134 | - << std::endl | ||
| 135 | - << std::endl | ||
| 136 | - << "Unless required by applicable law or agreed to in writing, software" | ||
| 137 | - << std::endl | ||
| 138 | - << "distributed under the License is distributed on an \"AS IS\" BASIS," | ||
| 139 | - << std::endl | ||
| 140 | - << "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied." | ||
| 141 | - << std::endl | ||
| 142 | - << "See the License for the specific language governing permissions and" | ||
| 143 | - << std::endl | ||
| 144 | - << "limitations under the License." | ||
| 145 | - << std::endl | ||
| 146 | - << std::endl | ||
| 147 | - << "Versions of qpdf prior to version 7 were released under the terms" | ||
| 148 | - << std::endl | ||
| 149 | - << "of version 2.0 of the Artistic License. At your option, you may" | ||
| 150 | - << std::endl | ||
| 151 | - << "continue to consider qpdf to be licensed under those terms. Please" | ||
| 152 | - << std::endl | ||
| 153 | - << "see the manual for additional information." | ||
| 154 | - << std::endl; | 123 | + << " version " << QPDF::QPDFVersion() << "\n" |
| 124 | + << "\n" | ||
| 125 | + << "Copyright (c) 2005-2022 Jay Berkenbilt\n" | ||
| 126 | + << "QPDF is licensed under the Apache License, Version 2.0 (the \"License\");\n" | ||
| 127 | + << "you may not use this file except in compliance with the License.\n" | ||
| 128 | + << "You may obtain a copy of the License at\n" | ||
| 129 | + << "\n" | ||
| 130 | + << " http://www.apache.org/licenses/LICENSE-2.0\n" | ||
| 131 | + << "\n" | ||
| 132 | + << "Unless required by applicable law or agreed to in writing, software\n" | ||
| 133 | + << "distributed under the License is distributed on an \"AS IS\" BASIS,\n" | ||
| 134 | + << "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" | ||
| 135 | + << "See the License for the specific language governing permissions and\n" | ||
| 136 | + << "limitations under the License.\n" | ||
| 137 | + << "\n" | ||
| 138 | + << "Versions of qpdf prior to version 7 were released under the terms\n" | ||
| 139 | + << "of version 2.0 of the Artistic License. At your option, you may\n" | ||
| 140 | + << "continue to consider qpdf to be licensed under those terms. Please\n" | ||
| 141 | + << "see the manual for additional information.\n"; | ||
| 155 | // clang-format on | 142 | // clang-format on |
| 156 | } | 143 | } |
| 157 | 144 | ||
| 158 | void | 145 | void |
| 159 | ArgParser::argJsonHelp() | 146 | ArgParser::argJsonHelp() |
| 160 | { | 147 | { |
| 161 | - std::cout << QPDFJob::json_out_schema_v1() << std::endl; | 148 | + *QPDFLogger::defaultLogger()->getInfo() |
| 149 | + << QPDFJob::json_out_schema_v1() << "\n"; | ||
| 162 | } | 150 | } |
| 163 | 151 | ||
| 164 | void | 152 | void |
| @@ -166,10 +154,10 @@ ArgParser::argShowCrypto() | @@ -166,10 +154,10 @@ ArgParser::argShowCrypto() | ||
| 166 | { | 154 | { |
| 167 | auto crypto = QPDFCryptoProvider::getRegisteredImpls(); | 155 | auto crypto = QPDFCryptoProvider::getRegisteredImpls(); |
| 168 | std::string default_crypto = QPDFCryptoProvider::getDefaultProvider(); | 156 | std::string default_crypto = QPDFCryptoProvider::getDefaultProvider(); |
| 169 | - std::cout << default_crypto << std::endl; | 157 | + *QPDFLogger::defaultLogger()->getInfo() << default_crypto << "\n"; |
| 170 | for (auto const& iter: crypto) { | 158 | for (auto const& iter: crypto) { |
| 171 | if (iter != default_crypto) { | 159 | if (iter != default_crypto) { |
| 172 | - std::cout << iter << std::endl; | 160 | + *QPDFLogger::defaultLogger()->getInfo() << iter << "\n"; |
| 173 | } | 161 | } |
| 174 | } | 162 | } |
| 175 | } | 163 | } |
| @@ -407,7 +395,8 @@ ArgParser::argEndCopyAttachment() | @@ -407,7 +395,8 @@ ArgParser::argEndCopyAttachment() | ||
| 407 | void | 395 | void |
| 408 | ArgParser::argJobJsonHelp() | 396 | ArgParser::argJobJsonHelp() |
| 409 | { | 397 | { |
| 410 | - std::cout << QPDFJob::job_json_schema_v1() << std::endl; | 398 | + *QPDFLogger::defaultLogger()->getInfo() |
| 399 | + << QPDFJob::job_json_schema_v1() << "\n"; | ||
| 411 | } | 400 | } |
| 412 | 401 | ||
| 413 | void | 402 | void |
libqpdf/QPDFJob_config.cc
| 1 | #include <qpdf/QPDFJob.hh> | 1 | #include <qpdf/QPDFJob.hh> |
| 2 | 2 | ||
| 3 | +#include <qpdf/QPDFLogger.hh> | ||
| 3 | #include <qpdf/QTC.hh> | 4 | #include <qpdf/QTC.hh> |
| 4 | #include <qpdf/QUtil.hh> | 5 | #include <qpdf/QUtil.hh> |
| 5 | 6 | ||
| @@ -648,9 +649,10 @@ QPDFJob::Config::passwordFile(std::string const& parameter) | @@ -648,9 +649,10 @@ QPDFJob::Config::passwordFile(std::string const& parameter) | ||
| 648 | o.m->password = QUtil::make_shared_cstr(lines.front()); | 649 | o.m->password = QUtil::make_shared_cstr(lines.front()); |
| 649 | 650 | ||
| 650 | if (lines.size() > 1) { | 651 | if (lines.size() > 1) { |
| 651 | - std::cerr << this->o.m->message_prefix | ||
| 652 | - << ": WARNING: all but the first line of" | ||
| 653 | - << " the password file are ignored" << std::endl; | 652 | + *QPDFLogger::defaultLogger()->getError() |
| 653 | + << this->o.m->message_prefix | ||
| 654 | + << ": WARNING: all but the first line of" | ||
| 655 | + << " the password file are ignored\n"; | ||
| 654 | } | 656 | } |
| 655 | } | 657 | } |
| 656 | return this; | 658 | return this; |
libqpdf/QPDFObjectHandle.cc
| @@ -5,6 +5,7 @@ | @@ -5,6 +5,7 @@ | ||
| 5 | #include <qpdf/Pl_QPDFTokenizer.hh> | 5 | #include <qpdf/Pl_QPDFTokenizer.hh> |
| 6 | #include <qpdf/QPDF.hh> | 6 | #include <qpdf/QPDF.hh> |
| 7 | #include <qpdf/QPDFExc.hh> | 7 | #include <qpdf/QPDFExc.hh> |
| 8 | +#include <qpdf/QPDFLogger.hh> | ||
| 8 | #include <qpdf/QPDFMatrix.hh> | 9 | #include <qpdf/QPDFMatrix.hh> |
| 9 | #include <qpdf/QPDFPageObjectHelper.hh> | 10 | #include <qpdf/QPDFPageObjectHelper.hh> |
| 10 | #include <qpdf/QPDF_Array.hh> | 11 | #include <qpdf/QPDF_Array.hh> |
| @@ -578,13 +579,12 @@ QPDFObjectHandle::getIntValueAsInt() | @@ -578,13 +579,12 @@ QPDFObjectHandle::getIntValueAsInt() | ||
| 578 | if (v < INT_MIN) { | 579 | if (v < INT_MIN) { |
| 579 | QTC::TC("qpdf", "QPDFObjectHandle int returning INT_MIN"); | 580 | QTC::TC("qpdf", "QPDFObjectHandle int returning INT_MIN"); |
| 580 | warnIfPossible( | 581 | warnIfPossible( |
| 581 | - "requested value of integer is too small; returning INT_MIN", | ||
| 582 | - false); | 582 | + "requested value of integer is too small; returning INT_MIN"); |
| 583 | result = INT_MIN; | 583 | result = INT_MIN; |
| 584 | } else if (v > INT_MAX) { | 584 | } else if (v > INT_MAX) { |
| 585 | QTC::TC("qpdf", "QPDFObjectHandle int returning INT_MAX"); | 585 | QTC::TC("qpdf", "QPDFObjectHandle int returning INT_MAX"); |
| 586 | warnIfPossible( | 586 | warnIfPossible( |
| 587 | - "requested value of integer is too big; returning INT_MAX", false); | 587 | + "requested value of integer is too big; returning INT_MAX"); |
| 588 | result = INT_MAX; | 588 | result = INT_MAX; |
| 589 | } else { | 589 | } else { |
| 590 | result = static_cast<int>(v); | 590 | result = static_cast<int>(v); |
| @@ -610,7 +610,7 @@ QPDFObjectHandle::getUIntValue() | @@ -610,7 +610,7 @@ QPDFObjectHandle::getUIntValue() | ||
| 610 | if (v < 0) { | 610 | if (v < 0) { |
| 611 | QTC::TC("qpdf", "QPDFObjectHandle uint returning 0"); | 611 | QTC::TC("qpdf", "QPDFObjectHandle uint returning 0"); |
| 612 | warnIfPossible( | 612 | warnIfPossible( |
| 613 | - "unsigned value request for negative number; returning 0", false); | 613 | + "unsigned value request for negative number; returning 0"); |
| 614 | } else { | 614 | } else { |
| 615 | result = static_cast<unsigned long long>(v); | 615 | result = static_cast<unsigned long long>(v); |
| 616 | } | 616 | } |
| @@ -635,15 +635,12 @@ QPDFObjectHandle::getUIntValueAsUInt() | @@ -635,15 +635,12 @@ QPDFObjectHandle::getUIntValueAsUInt() | ||
| 635 | if (v < 0) { | 635 | if (v < 0) { |
| 636 | QTC::TC("qpdf", "QPDFObjectHandle uint uint returning 0"); | 636 | QTC::TC("qpdf", "QPDFObjectHandle uint uint returning 0"); |
| 637 | warnIfPossible( | 637 | warnIfPossible( |
| 638 | - "unsigned integer value request for negative number; returning 0", | ||
| 639 | - false); | 638 | + "unsigned integer value request for negative number; returning 0"); |
| 640 | result = 0; | 639 | result = 0; |
| 641 | } else if (v > UINT_MAX) { | 640 | } else if (v > UINT_MAX) { |
| 642 | QTC::TC("qpdf", "QPDFObjectHandle uint returning UINT_MAX"); | 641 | QTC::TC("qpdf", "QPDFObjectHandle uint returning UINT_MAX"); |
| 643 | - warnIfPossible( | ||
| 644 | - "requested value of unsigned integer is too big;" | ||
| 645 | - " returning UINT_MAX", | ||
| 646 | - false); | 642 | + warnIfPossible("requested value of unsigned integer is too big;" |
| 643 | + " returning UINT_MAX"); | ||
| 647 | result = UINT_MAX; | 644 | result = UINT_MAX; |
| 648 | } else { | 645 | } else { |
| 649 | result = static_cast<unsigned int>(v); | 646 | result = static_cast<unsigned int>(v); |
| @@ -3000,16 +2997,15 @@ QPDFObjectHandle::typeWarning( | @@ -3000,16 +2997,15 @@ QPDFObjectHandle::typeWarning( | ||
| 3000 | } | 2997 | } |
| 3001 | 2998 | ||
| 3002 | void | 2999 | void |
| 3003 | -QPDFObjectHandle::warnIfPossible( | ||
| 3004 | - std::string const& warning, bool throw_if_no_description) | 3000 | +QPDFObjectHandle::warnIfPossible(std::string const& warning) |
| 3005 | { | 3001 | { |
| 3006 | QPDF* context = 0; | 3002 | QPDF* context = 0; |
| 3007 | std::string description; | 3003 | std::string description; |
| 3008 | dereference(); | 3004 | dereference(); |
| 3009 | if (this->obj->getDescription(context, description)) { | 3005 | if (this->obj->getDescription(context, description)) { |
| 3010 | warn(context, QPDFExc(qpdf_e_damaged_pdf, "", description, 0, warning)); | 3006 | warn(context, QPDFExc(qpdf_e_damaged_pdf, "", description, 0, warning)); |
| 3011 | - } else if (throw_if_no_description) { | ||
| 3012 | - throw std::runtime_error(warning); | 3007 | + } else { |
| 3008 | + *QPDFLogger::defaultLogger()->getError() << warning << "\n"; | ||
| 3013 | } | 3009 | } |
| 3014 | } | 3010 | } |
| 3015 | 3011 |
libqpdf/qpdf-c.cc
| @@ -6,6 +6,7 @@ | @@ -6,6 +6,7 @@ | ||
| 6 | #include <qpdf/Pl_Discard.hh> | 6 | #include <qpdf/Pl_Discard.hh> |
| 7 | #include <qpdf/QIntC.hh> | 7 | #include <qpdf/QIntC.hh> |
| 8 | #include <qpdf/QPDFExc.hh> | 8 | #include <qpdf/QPDFExc.hh> |
| 9 | +#include <qpdf/QPDFLogger.hh> | ||
| 9 | #include <qpdf/QPDFWriter.hh> | 10 | #include <qpdf/QPDFWriter.hh> |
| 10 | #include <qpdf/QTC.hh> | 11 | #include <qpdf/QTC.hh> |
| 11 | #include <qpdf/QUtil.hh> | 12 | #include <qpdf/QUtil.hh> |
| @@ -185,8 +186,9 @@ qpdf_cleanup(qpdf_data* qpdf) | @@ -185,8 +186,9 @@ qpdf_cleanup(qpdf_data* qpdf) | ||
| 185 | qpdf_oh_release_all(*qpdf); | 186 | qpdf_oh_release_all(*qpdf); |
| 186 | if ((*qpdf)->error.get()) { | 187 | if ((*qpdf)->error.get()) { |
| 187 | QTC::TC("qpdf", "qpdf-c cleanup warned about unhandled error"); | 188 | QTC::TC("qpdf", "qpdf-c cleanup warned about unhandled error"); |
| 188 | - std::cerr << "WARNING: application did not handle error: " | ||
| 189 | - << (*qpdf)->error->what() << std::endl; | 189 | + *QPDFLogger::defaultLogger()->getWarn() |
| 190 | + << "WARNING: application did not handle error: " | ||
| 191 | + << (*qpdf)->error->what() << "\n"; | ||
| 190 | } | 192 | } |
| 191 | delete *qpdf; | 193 | delete *qpdf; |
| 192 | *qpdf = 0; | 194 | *qpdf = 0; |
| @@ -898,7 +900,8 @@ trap_oh_errors( | @@ -898,7 +900,8 @@ trap_oh_errors( | ||
| 898 | " to ERROR HANDLING in qpdf-c.h")); | 900 | " to ERROR HANDLING in qpdf-c.h")); |
| 899 | qpdf->oh_error_occurred = true; | 901 | qpdf->oh_error_occurred = true; |
| 900 | } | 902 | } |
| 901 | - std::cerr << qpdf->error->what() << std::endl; | 903 | + *QPDFLogger::defaultLogger()->getError() |
| 904 | + << qpdf->error->what() << "\n"; | ||
| 902 | } | 905 | } |
| 903 | return fallback(); | 906 | return fallback(); |
| 904 | } | 907 | } |
libqpdf/qpdfjob-c.cc
| 1 | #include <qpdf/qpdfjob-c.h> | 1 | #include <qpdf/qpdfjob-c.h> |
| 2 | 2 | ||
| 3 | #include <qpdf/QPDFJob.hh> | 3 | #include <qpdf/QPDFJob.hh> |
| 4 | +#include <qpdf/QPDFLogger.hh> | ||
| 4 | #include <qpdf/QPDFUsage.hh> | 5 | #include <qpdf/QPDFUsage.hh> |
| 5 | #include <qpdf/QUtil.hh> | 6 | #include <qpdf/QUtil.hh> |
| 6 | 7 | ||
| @@ -19,7 +20,8 @@ qpdfjob_run_from_argv(char const* const argv[]) | @@ -19,7 +20,8 @@ qpdfjob_run_from_argv(char const* const argv[]) | ||
| 19 | j.initializeFromArgv(argv); | 20 | j.initializeFromArgv(argv); |
| 20 | j.run(); | 21 | j.run(); |
| 21 | } catch (std::exception& e) { | 22 | } catch (std::exception& e) { |
| 22 | - std::cerr << whoami << ": " << e.what() << std::endl; | 23 | + *QPDFLogger::defaultLogger()->getError() |
| 24 | + << whoami << ": " << e.what() << "\n"; | ||
| 23 | return QPDFJob::EXIT_ERROR; | 25 | return QPDFJob::EXIT_ERROR; |
| 24 | } | 26 | } |
| 25 | return j.getExitCode(); | 27 | return j.getExitCode(); |
| @@ -48,7 +50,8 @@ qpdfjob_run_from_json(char const* json) | @@ -48,7 +50,8 @@ qpdfjob_run_from_json(char const* json) | ||
| 48 | j.initializeFromJson(json); | 50 | j.initializeFromJson(json); |
| 49 | j.run(); | 51 | j.run(); |
| 50 | } catch (std::exception& e) { | 52 | } catch (std::exception& e) { |
| 51 | - std::cerr << "qpdfjob json: " << e.what() << std::endl; | 53 | + *QPDFLogger::defaultLogger()->getError() |
| 54 | + << "qpdfjob json: " << e.what() << "\n"; | ||
| 52 | return QPDFJob::EXIT_ERROR; | 55 | return QPDFJob::EXIT_ERROR; |
| 53 | } | 56 | } |
| 54 | return j.getExitCode(); | 57 | return j.getExitCode(); |
manual/release-notes.rst
| @@ -120,6 +120,11 @@ For a detailed list of changes, please see the file | @@ -120,6 +120,11 @@ For a detailed list of changes, please see the file | ||
| 120 | - See :ref:`breaking-crypto-api` for specific details, and see | 120 | - See :ref:`breaking-crypto-api` for specific details, and see |
| 121 | :ref:`weak-crypto` for a general discussion. | 121 | :ref:`weak-crypto` for a general discussion. |
| 122 | 122 | ||
| 123 | + - QPDFObjectHandle::warnIfPossible no longer takes an optional | ||
| 124 | + argument to throw an exception if there is no description. If | ||
| 125 | + there is no description, it writes to the default logger's error | ||
| 126 | + stream. | ||
| 127 | + | ||
| 123 | - CLI Enhancements | 128 | - CLI Enhancements |
| 124 | 129 | ||
| 125 | - ``qpdf --list-attachments --verbose`` include some additional | 130 | - ``qpdf --list-attachments --verbose`` include some additional |
| @@ -139,6 +144,20 @@ For a detailed list of changes, please see the file | @@ -139,6 +144,20 @@ For a detailed list of changes, please see the file | ||
| 139 | 144 | ||
| 140 | - Library Enhancements | 145 | - Library Enhancements |
| 141 | 146 | ||
| 147 | + - A new object ``QPDFLogger`` has been added. Details are in | ||
| 148 | + :file:`include/qpdf/QPDFLogger.hh`. | ||
| 149 | + | ||
| 150 | + - ``QPDF`` and ``QPDFJob`` both use the default logger by | ||
| 151 | + default but can have their loggers overridden. The | ||
| 152 | + ``setOutputStreams`` method is deprecated in both classes. | ||
| 153 | + | ||
| 154 | + - A few things from ``QPDFObjectHandle`` that used to be | ||
| 155 | + exceptions now write errors with the default logger. | ||
| 156 | + | ||
| 157 | + - By configuring the default logger, it is possible to capture | ||
| 158 | + output and errors that slipped through the cracks with | ||
| 159 | + ``setOutputStreams``. | ||
| 160 | + | ||
| 142 | - New methods ``insertItemAndGet``, ``appendItemAndGet``, | 161 | - New methods ``insertItemAndGet``, ``appendItemAndGet``, |
| 143 | ``eraseItemAndGet``, ``replaceKeyAndGet``, and | 162 | ``eraseItemAndGet``, ``replaceKeyAndGet``, and |
| 144 | ``removeKeyAndGet`` return the newly added or removed object. | 163 | ``removeKeyAndGet`` return the newly added or removed object. |
qpdf/qtest/error-condition.test
| @@ -111,11 +111,11 @@ $td->runtest("C API: no recovery", | @@ -111,11 +111,11 @@ $td->runtest("C API: no recovery", | ||
| 111 | 111 | ||
| 112 | $td->runtest("integer type checks", | 112 | $td->runtest("integer type checks", |
| 113 | {$td->COMMAND => "test_driver 62 minimal.pdf"}, | 113 | {$td->COMMAND => "test_driver 62 minimal.pdf"}, |
| 114 | - {$td->STRING => "test 62 done\n", $td->EXIT_STATUS => 0}, | 114 | + {$td->FILE => "test62.out", $td->EXIT_STATUS => 0}, |
| 115 | $td->NORMALIZE_NEWLINES); | 115 | $td->NORMALIZE_NEWLINES); |
| 116 | $td->runtest("getValueAs... accessor checks", | 116 | $td->runtest("getValueAs... accessor checks", |
| 117 | {$td->COMMAND => "test_driver 85 -"}, | 117 | {$td->COMMAND => "test_driver 85 -"}, |
| 118 | - {$td->STRING => "test 85 done\n", $td->EXIT_STATUS => 0}, | 118 | + {$td->FILE => "test85.out", $td->EXIT_STATUS => 0}, |
| 119 | $td->NORMALIZE_NEWLINES); | 119 | $td->NORMALIZE_NEWLINES); |
| 120 | 120 | ||
| 121 | $n_tests += @badfiles + 11; | 121 | $n_tests += @badfiles + 11; |
qpdf/qtest/qpdf/test62.out
0 → 100644
| 1 | +requested value of integer is too big; returning INT_MAX | ||
| 2 | +requested value of unsigned integer is too big; returning UINT_MAX | ||
| 3 | +unsigned value request for negative number; returning 0 | ||
| 4 | +requested value of integer is too small; returning INT_MIN | ||
| 5 | +unsigned integer value request for negative number; returning 0 | ||
| 6 | +requested value of integer is too big; returning INT_MAX | ||
| 7 | +test 62 done |
qpdf/qtest/qpdf/test85.out
0 → 100644
| 1 | +requested value of integer is too big; returning INT_MAX | ||
| 2 | +requested value of integer is too small; returning INT_MIN | ||
| 3 | +unsigned value request for negative number; returning 0 | ||
| 4 | +unsigned integer value request for negative number; returning 0 | ||
| 5 | +requested value of unsigned integer is too big; returning UINT_MAX | ||
| 6 | +test 85 done |